Compare commits
263 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d56aa41e9e | |||
| 5778558dae | |||
| b7bf868042 | |||
| 06c20c4675 | |||
| f30a2bb18e | |||
| 92a2dcc96a | |||
| 3a694fd6bf | |||
| bb6a65da42 | |||
| a11ffea697 | |||
| 90d7307872 | |||
| 453dfc4f94 | |||
| 75bffe9d96 | |||
| 22dc6301f0 | |||
| 7266fa1524 | |||
| e0a09f31b1 | |||
| 72526c6f49 | |||
| 5c0f33209e | |||
| 943ee4d484 | |||
| acd31294f4 | |||
| b409287479 | |||
| 13d98b9f6e | |||
| 2b19e45d49 | |||
| 7bde04468b | |||
| 80b23a2afd | |||
| da8e201e17 | |||
| d6950db0d9 | |||
| 661d66b452 | |||
| 74a5cc0965 | |||
| 768a82b583 | |||
| 04d3db34ee | |||
| c871b4d5f8 | |||
| d3749a82ab | |||
| d7610a257f | |||
| 62b840648d | |||
| 5f93e6ab03 | |||
| 69beec3d2a | |||
| d2c9c79c0e | |||
| 1ce15ab9b1 | |||
| a24d8a0d2a | |||
| 8835ecef16 | |||
| 86c79ed091 | |||
| d4f5e92ee1 | |||
| 2c58f9533b | |||
| 34077a9190 | |||
| 42726d645c | |||
| 02d08d2e4d | |||
| 9b90cf6584 | |||
| bdbc077efc | |||
| fb06894e75 | |||
| 6b4946e0a8 | |||
| 057f63909f | |||
| ea84a13152 | |||
| 9639feb9a3 | |||
| f009e2621e | |||
| 3449379bca | |||
| c77d6a79ec | |||
| d8558b1d42 | |||
| b8614dee98 | |||
| b852d34285 | |||
| 250ef211f0 | |||
| 2ebcdda606 | |||
| ce89c63b0b | |||
| 8acc343fb8 | |||
| 15a54747b9 | |||
| 7666131199 | |||
| 8b54213ad0 | |||
| 561a371423 | |||
| 6cc39f8e94 | |||
| 58e54a3d33 | |||
| eb1c1e79a1 | |||
| e7c973a195 | |||
| a982ebad0c | |||
| 27692e70b5 | |||
| 05db16c24d | |||
| 0aaf7fe953 | |||
| aea9770cfc | |||
| 05fe39a88f | |||
| 44305df587 | |||
| 638caa1355 | |||
| 6d29dc587e | |||
| 0f03ac03b5 | |||
| a11b849ebe | |||
| 4cfa5bca7c | |||
| 19ad8459d7 | |||
| 3f6919adc7 | |||
| 5d2ce59559 | |||
| e08dd90c32 | |||
| 26d7f16686 | |||
| 5b168b055f | |||
| 7ad936dcbf | |||
| 29ab56c4d2 | |||
| 6c640dacf4 | |||
| 234d24dfea | |||
| 835505681c | |||
| e930abfcf8 | |||
| cb06a0a271 | |||
| f8f19a4d8e | |||
| e2a8d063ee | |||
| 1fd2f0364c | |||
| 7f450dcea3 | |||
| c39a3357ed | |||
| cc10212366 | |||
| df2b3113d9 | |||
| d4f428311a | |||
| e2c677c3e8 | |||
| 80b3cb4951 | |||
| dfa5124909 | |||
| d3a6c97a43 | |||
| 316a50f2b7 | |||
| 2883fd28e4 | |||
| aa7f8f9e09 | |||
| c4b56bb393 | |||
| 156d214635 | |||
| 31b07a6298 | |||
| 2c82466444 | |||
| 91e70280a2 | |||
| 68e93dbfee | |||
| c12d07d9d4 | |||
| a29ef48500 | |||
| 0fae681a7c | |||
| 149df44e29 | |||
| da1fafe59d | |||
| 3821c707b8 | |||
| 1c7a5d9972 | |||
| 0fdbf26fd0 | |||
| 4f3c3432cd | |||
| b6715bb1ae | |||
| 40094ddbe0 | |||
| 8535c32bf3 | |||
| 6b90c69bda | |||
| 6f3337dcba | |||
| ff33f82ac2 | |||
| bf6cf572ca | |||
| 433109e2ac | |||
| 07bfca9041 | |||
| b2320ccd71 | |||
| 5e4ba1f036 | |||
| 7e17945088 | |||
| 535e970ad3 | |||
| dd8595035f | |||
| 06ae387ca5 | |||
| df48a73c5c | |||
| 70bbb44030 | |||
| 70ab78478f | |||
| 8a66b2b99a | |||
| ee5ac3f1f3 | |||
| 9e71503ab3 | |||
| 651ecb52d9 | |||
| 85845b13d7 | |||
| 7b0946129c | |||
| 7d7cfee0b7 | |||
| 6751ba6500 | |||
| 6d387e4b2b | |||
| ed3b73d9fc | |||
| f95b010ec5 | |||
| 97060da478 | |||
| 9715fd56da | |||
| 7e3d7fb02d | |||
| a9cc2ebb6e | |||
| 1a7ec4cf3d | |||
| 7715c626ad | |||
| 1c9098aeb8 | |||
| 5d18431087 | |||
| 0d27c76e34 | |||
| 8deeed9771 | |||
| 7893a34171 | |||
| e6966b7ae7 | |||
| 3e81ebecb6 | |||
| f9c5802f4e | |||
| e6ee7a5b1c | |||
| 17081ee902 | |||
| e817dd70db | |||
| bc30a904f4 | |||
| b2d9c6ff81 | |||
| 18dae18e20 | |||
| 18c7f3cdf3 | |||
| f0b462209a | |||
| 974db25816 | |||
| 7a02ae5644 | |||
| a9f24ce125 | |||
| a68fcabc65 | |||
| 2978ffc4a5 | |||
| a694661d5c | |||
| 7d77854fd6 | |||
| 17124e62a9 | |||
| d9ae012d15 | |||
| c03706fafb | |||
| f77aa8c4a7 | |||
| 4044abd156 | |||
| 6164556c85 | |||
| 69a8f920d4 | |||
| ff263b6dbc | |||
| 763c71194b | |||
| 19ac0728f2 | |||
| 39cb2a03e5 | |||
| c8c84b4af1 | |||
| 5ec01a7226 | |||
| f878e05d62 | |||
| aa0e2cffdd | |||
| c18b59808c | |||
| a0d8c025f7 | |||
| 137d311fd1 | |||
| 57f20b6cb3 | |||
| a10506b8d7 | |||
| 28b8fc9896 | |||
| f55b829f44 | |||
| 836b2c23a2 | |||
| 0068701bc6 | |||
| 83a978d1cd | |||
| d05795db8e | |||
| 629a7066be | |||
| 058b11e57b | |||
| aa230649d9 | |||
| f8cce391b2 | |||
| a7d476c35f | |||
| 5425fb3d79 | |||
| 587d737690 | |||
| 31b68a2b5d | |||
| a48f00d940 | |||
| f7da739ea0 | |||
| ebb346cd8e | |||
| b39d8d5027 | |||
| cf48f359ad | |||
| 8ac29c9422 | |||
| 7f3617860c | |||
| b35f70ce14 | |||
| 77d0c0caa9 | |||
| c2193308a6 | |||
| 9456911fe9 | |||
| bd2c8fdd54 | |||
| 234d81e39b | |||
| 9747b5b26b | |||
| 508d462fa7 | |||
| f687e02dec | |||
| 72c3038925 | |||
| d393030c58 | |||
| d68ea84924 | |||
| 85825dcc55 | |||
| 80f152296c | |||
| 48aa9aae56 | |||
| 025065daf5 | |||
| 49be0febdc | |||
| 73f57aab98 | |||
| 457f0e9384 | |||
| 4b15c803e2 | |||
| 50aff515b7 | |||
| 5b33398f07 | |||
| 47568f31c5 | |||
| eba83406da | |||
| 137c6f36bb | |||
| d9043b324d | |||
| e57e560385 | |||
| eebd5742b6 | |||
| 0837a24c05 | |||
| f2e48b39f6 | |||
| 5060c53176 | |||
| 3f392e934e | |||
| c1e4679ed5 | |||
| 9254b7e75a | |||
| 1d609ca0ee | |||
| 61fabd3e73 | |||
| 58acb96ee6 | |||
| b564a40d74 |
@@ -3,7 +3,7 @@ name: Core
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- master
|
||||
- main
|
||||
- MOODLE_[0-9]+_STABLE
|
||||
tags-ignore:
|
||||
- v[0-9]+.[0-9]+.[0-9]+*
|
||||
|
||||
@@ -4504,6 +4504,203 @@
|
||||
</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>
|
||||
<MOODLE version="4.5" requires="4.1.2">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.6.7" />
|
||||
<VENDOR name="mysql" version="8.0" />
|
||||
<VENDOR name="postgres" version="13" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.1.0" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_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>
|
||||
|
||||
+5
-2
@@ -2052,8 +2052,10 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
// We are checking installed & enabled things
|
||||
if ($environment_result->getLevel() == 'required') {
|
||||
$stringtouse = 'environmentrequirecustomcheck';
|
||||
} else {
|
||||
} else if ($environment_result->getLevel() == 'optional') {
|
||||
$stringtouse = 'environmentrecommendcustomcheck';
|
||||
} else {
|
||||
$stringtouse = 'environmentshouldfixcustomcheck';
|
||||
}
|
||||
|
||||
} else if ($environment_result->getPart() == 'php_setting') {
|
||||
@@ -2084,7 +2086,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
if ($status) { //Handle ok result (ok)
|
||||
$status = get_string('statusok');
|
||||
} else {
|
||||
if ($environment_result->getLevel() == 'optional') {//Handle check result (warning)
|
||||
// Handle check result (warning).
|
||||
if (in_array($environment_result->getLevel(), ['optional', 'recommended'])) {
|
||||
$status = get_string('check');
|
||||
$warningline = true;
|
||||
} else { //Handle error result (error)
|
||||
|
||||
@@ -152,7 +152,8 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$sensiblesettingsdefault .= 'server_password@@search_solr, ssl_keypassword@@search_solr, ';
|
||||
$sensiblesettingsdefault .= 'alternateserver_password@@search_solr, alternatessl_keypassword@@search_solr, ';
|
||||
$sensiblesettingsdefault .= 'test_password@@cachestore_redis, password@@mlbackend_python, ';
|
||||
$sensiblesettingsdefault .= 'badges_badgesalt@@none, calendar_exportsalt@@none';
|
||||
$sensiblesettingsdefault .= 'badges_badgesalt@@none, calendar_exportsalt@@none, ';
|
||||
$sensiblesettingsdefault .= 'bigbluebuttonbn_shared_secret@@none';
|
||||
$temp->add(new admin_setting_configtextarea('adminpresets/sensiblesettings',
|
||||
get_string('sensiblesettings', 'core_adminpresets'),
|
||||
get_string('sensiblesettingstext', 'core_adminpresets'),
|
||||
|
||||
@@ -18,7 +18,7 @@ Feature: An administrator can browse user accounts
|
||||
When I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
# Name field always present, email field is default for showidentity.
|
||||
Then the following should exist in the "users" table:
|
||||
| First name / Last name | Email address |
|
||||
| First name | Email address |
|
||||
| User One | one@example.com |
|
||||
| User Two | two@example.com |
|
||||
# Should not see other identity fields or non-default name fields.
|
||||
@@ -34,7 +34,7 @@ Feature: An administrator can browse user accounts
|
||||
| alternativefullnameformat | firstnamephonetic lastname |
|
||||
When I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
Then the following should exist in the "users" table:
|
||||
| First name - phonetic / Last name | Email address |
|
||||
| First name - phonetic | Email address |
|
||||
| Yewzer One | one@example.com |
|
||||
| Yoozare Two | two@example.com |
|
||||
|
||||
@@ -43,7 +43,7 @@ Feature: An administrator can browse user accounts
|
||||
| showuseridentity | department,profile_field_frog |
|
||||
When I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
Then the following should exist in the "users" table:
|
||||
| First name / Last name | Favourite frog | Department |
|
||||
| First name | Favourite frog | Department |
|
||||
| User One | Kermit | Attack |
|
||||
| User Two | Tree | Defence |
|
||||
And I should not see "Email address" in the "table" "css_element"
|
||||
|
||||
@@ -48,25 +48,3 @@ Feature: View task logs report and use its filters
|
||||
| operator | shouldornotsee |
|
||||
| Less than | should not see |
|
||||
| Greater than | should see |
|
||||
|
||||
@javascript
|
||||
Scenario: Reset task log filters
|
||||
Given I log in as "admin"
|
||||
And I change window size to "large"
|
||||
And I navigate to "Server > Tasks > Task logs" in site administration
|
||||
When I click on "Filters" "button"
|
||||
And I set the following fields in the "Result" "core_reportbuilder > Filter" to these values:
|
||||
| Result operator | Is equal to |
|
||||
| Result value | Fail |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
Then I should see "Filters applied"
|
||||
And I should see "Filters (1)" in the "#dropdownFiltersButton" "css_element"
|
||||
And I should see "Nothing to display"
|
||||
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I should see "Filters reset"
|
||||
And I should not see "Filters (1)" in the "#dropdownFiltersButton" "css_element"
|
||||
And I should see "Filters" in the "#dropdownFiltersButton" "css_element"
|
||||
And "[data-region='report-filters']" "css_element" should be visible
|
||||
And the following fields in the "Result" "core_reportbuilder > Filter" match these values:
|
||||
| Result operator | Is any value |
|
||||
And I should not see "Nothing to display"
|
||||
|
||||
@@ -5,16 +5,18 @@ Feature: I can download a preset
|
||||
| name |
|
||||
| Custom preset |
|
||||
|
||||
@javascript
|
||||
Scenario: Custom preset settings can be downloaded
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Site admin presets" in site administration
|
||||
When I open the action menu in "Custom preset" "table_row"
|
||||
Then following "Download" "link" in the "Custom preset" "table_row" should download between "0" and "5000" bytes
|
||||
Then following "Download" in the "Custom preset" "table_row" should download a file that:
|
||||
| Has mimetype | text/xml |
|
||||
| Contains text in xml element | Custom preset |
|
||||
|
||||
@javascript
|
||||
Scenario: Core preset settings can be downloaded
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Site admin presets" in site administration
|
||||
When I open the action menu in "Starter" "table_row"
|
||||
Then following "Download" "link" in the "Starter" "table_row" should download between "0" and "5000" bytes
|
||||
Then following "Download" in the "Starter" "table_row" should download a file that:
|
||||
| Has mimetype | text/xml |
|
||||
| Contains text in xml element | Starter |
|
||||
|
||||
@@ -155,9 +155,9 @@ class data_request extends persistent {
|
||||
case api::DATAREQUEST_STATUS_EXPIRED:
|
||||
$result = true;
|
||||
break;
|
||||
// Complete requests are expired if the expiry time has elapsed.
|
||||
// Complete requests are expired if the expiry time is a positive value, and has elapsed.
|
||||
case api::DATAREQUEST_STATUS_DOWNLOAD_READY:
|
||||
$expiryseconds = get_config('tool_dataprivacy', 'privacyrequestexpiry');
|
||||
$expiryseconds = (int) get_config('tool_dataprivacy', 'privacyrequestexpiry');
|
||||
if ($expiryseconds > 0 && time() >= ($request->get('timemodified') + $expiryseconds)) {
|
||||
$result = true;
|
||||
}
|
||||
@@ -178,7 +178,12 @@ class data_request extends persistent {
|
||||
public static function get_expired_requests($userid = 0) {
|
||||
global $DB;
|
||||
|
||||
$expiryseconds = get_config('tool_dataprivacy', 'privacyrequestexpiry');
|
||||
// Complete requests are expired if the expiry time is a positive value, and has elapsed.
|
||||
$expiryseconds = (int) get_config('tool_dataprivacy', 'privacyrequestexpiry');
|
||||
if ($expiryseconds <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$expirytime = strtotime("-{$expiryseconds} second");
|
||||
$table = self::TABLE;
|
||||
$sqlwhere = 'type = :export_type AND status = :completestatus AND timemodified <= :expirytime';
|
||||
|
||||
@@ -54,6 +54,7 @@ Feature: Data delete from the privacy API
|
||||
And I should see "Awaiting approval" in the "Victim User 1" "table_row"
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And I follow "Approve request"
|
||||
And I wait until "Approve request" "button" exists
|
||||
And I press "Approve request"
|
||||
And I should see "Approved" in the "Victim User 1" "table_row"
|
||||
And I run all adhoc tasks
|
||||
@@ -80,6 +81,7 @@ Feature: Data delete from the privacy API
|
||||
And I navigate to "Users > Privacy and policies > Data requests" in site administration
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And I follow "Approve request"
|
||||
And I wait until "Approve request" "button" exists
|
||||
And I press "Approve request"
|
||||
|
||||
And I log out
|
||||
@@ -115,6 +117,7 @@ Feature: Data delete from the privacy API
|
||||
And I navigate to "Users > Privacy and policies > Data requests" in site administration
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And I follow "Approve request"
|
||||
And I wait until "Approve request" "button" exists
|
||||
And I press "Approve request"
|
||||
|
||||
And I log out
|
||||
|
||||
@@ -48,13 +48,15 @@ Feature: Data export from the privacy API
|
||||
And I should see "Awaiting approval" in the "Victim User 1" "table_row"
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And I follow "Approve request"
|
||||
And I wait until "Approve request" "button" exists
|
||||
And I press "Approve request"
|
||||
And I should see "Approved" in the "Victim User 1" "table_row"
|
||||
And I run all adhoc tasks
|
||||
And I reload the page
|
||||
And I should see "Download ready" in the "Victim User 1" "table_row"
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And following "Download" should download between "1" and "150000" bytes
|
||||
And following "Download" should download a file that:
|
||||
| Contains file in zip | index.html |
|
||||
And the following config values are set as admin:
|
||||
| privacyrequestexpiry | 1 | tool_dataprivacy |
|
||||
And I wait "1" seconds
|
||||
@@ -89,7 +91,8 @@ Feature: Data export from the privacy API
|
||||
And I reload the page
|
||||
And I should see "Download ready" in the "Export all of my personal data" "table_row"
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And following "Download" should download between "1" and "155000" bytes
|
||||
And following "Download" should download a file that:
|
||||
| Contains file in zip | index.html |
|
||||
|
||||
And the following config values are set as admin:
|
||||
| privacyrequestexpiry | 1 | tool_dataprivacy |
|
||||
@@ -115,6 +118,7 @@ Feature: Data export from the privacy API
|
||||
And I navigate to "Users > Privacy and policies > Data requests" in site administration
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And I follow "Approve request"
|
||||
And I wait until "Approve request" "button" exists
|
||||
And I press "Approve request"
|
||||
|
||||
And I log out
|
||||
@@ -126,7 +130,8 @@ Feature: Data export from the privacy API
|
||||
And I reload the page
|
||||
And I should see "Download ready" in the "Victim User 1" "table_row"
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And following "Download" should download between "1" and "150000" bytes
|
||||
And following "Download" should download a file that:
|
||||
| Contains file in zip | index.html |
|
||||
|
||||
And the following config values are set as admin:
|
||||
| privacyrequestexpiry | 1 | tool_dataprivacy |
|
||||
|
||||
@@ -26,10 +26,11 @@ require_once('data_privacy_testcase.php');
|
||||
* Expired data requests tests.
|
||||
*
|
||||
* @package tool_dataprivacy
|
||||
* @covers \tool_dataprivacy\data_request
|
||||
* @copyright 2018 Michael Hawkins
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class expired_data_requests_test extends data_privacy_testcase {
|
||||
final class expired_data_requests_test extends data_privacy_testcase {
|
||||
|
||||
/**
|
||||
* Test tearDown.
|
||||
@@ -107,6 +108,52 @@ class expired_data_requests_test extends data_privacy_testcase {
|
||||
$this->assertEquals(0, $DB->count_records('files', $fileconditions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that data requests are not expired when expiration is disabled (set to zero)
|
||||
*/
|
||||
public function test_data_request_expiry_never(): void {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
\core_privacy\local\request\writer::setup_real_writer_instance();
|
||||
|
||||
// Disable request expiry.
|
||||
set_config('privacyrequestexpiry', 0, 'tool_dataprivacy');
|
||||
|
||||
// Create and approve data request.
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$usercontext = \context_user::instance($user->id);
|
||||
|
||||
$this->setUser($user->id);
|
||||
$datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT);
|
||||
$requestid = $datarequest->get('id');
|
||||
|
||||
$this->setAdminUser();
|
||||
api::approve_data_request($requestid);
|
||||
|
||||
ob_start();
|
||||
$this->runAdhocTasks('\tool_dataprivacy\task\process_data_request_task');
|
||||
ob_end_clean();
|
||||
|
||||
// Run expiry deletion - should not affect test export.
|
||||
$expiredrequests = data_request::get_expired_requests();
|
||||
$this->assertEmpty($expiredrequests);
|
||||
data_request::expire($expiredrequests);
|
||||
|
||||
// Confirm approved and exported.
|
||||
$request = new data_request($requestid);
|
||||
$this->assertEquals(api::DATAREQUEST_STATUS_DOWNLOAD_READY, $request->get('status'));
|
||||
$fileconditions = [
|
||||
'userid' => $user->id,
|
||||
'component' => 'tool_dataprivacy',
|
||||
'filearea' => 'export',
|
||||
'itemid' => $requestid,
|
||||
'contextid' => $usercontext->id,
|
||||
];
|
||||
$this->assertEquals(2, $DB->count_records('files', $fileconditions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for \tool_dataprivacy\data_request::is_expired()
|
||||
* Tests for the expected request status to protect from false positive/negative,
|
||||
|
||||
@@ -14,6 +14,6 @@ Feature: In a report, admin can see logstore visibility changes
|
||||
And I click on "Enable" "icon" in the "External database log" "table_row"
|
||||
And I navigate to "Reports > Config changes" in site administration
|
||||
Then the following should exist in the "reportbuilder-table" table:
|
||||
| User | Plugin | Setting | New value | Original value |
|
||||
| First name | Plugin | Setting | New value | Original value |
|
||||
| Admin User | logstore_standard | tool_logstore_visibility | 0 | 1 |
|
||||
| Admin User | logstore_database | tool_logstore_visibility | 1 | 0 |
|
||||
|
||||
@@ -419,13 +419,13 @@ class api {
|
||||
public static function get_qrlogin_key(stdClass $mobilesettings) {
|
||||
global $USER;
|
||||
// Delete previous keys.
|
||||
delete_user_key('tool_mobile', $USER->id);
|
||||
delete_user_key('tool_mobile/qrlogin', $USER->id);
|
||||
|
||||
// Create a new key.
|
||||
$iprestriction = !empty($mobilesettings->qrsameipcheck) ? getremoteaddr(null) : null;
|
||||
$qrkeyttl = !empty($mobilesettings->qrkeyttl) ? $mobilesettings->qrkeyttl : self::LOGIN_QR_KEY_TTL;
|
||||
$validuntil = time() + $qrkeyttl;
|
||||
return create_user_key('tool_mobile', $USER->id, null, $iprestriction, $validuntil);
|
||||
return create_user_key('tool_mobile/qrlogin', $USER->id, null, $iprestriction, $validuntil);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -649,8 +649,8 @@ class external extends external_api {
|
||||
api::check_autologin_prerequisites($params['userid']); // Checks https, avoid site admins using this...
|
||||
|
||||
// Validate and delete the key.
|
||||
$key = validate_user_key($params['qrloginkey'], 'tool_mobile', null);
|
||||
delete_user_key('tool_mobile', $params['userid']);
|
||||
$key = validate_user_key($params['qrloginkey'], 'tool_mobile/qrlogin', null);
|
||||
delete_user_key('tool_mobile/qrlogin', $params['userid']);
|
||||
|
||||
// Double check key belong to user.
|
||||
if ($key->userid != $params['userid']) {
|
||||
|
||||
@@ -66,7 +66,7 @@ class provider implements
|
||||
FROM {user_private_key} k
|
||||
JOIN {user} u ON k.userid = u.id
|
||||
JOIN {context} ctx ON ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel
|
||||
WHERE k.userid = :userid AND k.script = 'tool_mobile'";
|
||||
WHERE k.userid = :userid AND (k.script = 'tool_mobile' OR k.script = 'tool_mobile/qrlogin')";
|
||||
$params = ['userid' => $userid, 'contextlevel' => CONTEXT_USER];
|
||||
$contextlist = new contextlist();
|
||||
$contextlist->add_from_sql($sql, $params);
|
||||
@@ -88,6 +88,7 @@ class provider implements
|
||||
|
||||
// Add users based on userkey.
|
||||
\core_userkey\privacy\provider::get_user_contexts_with_script($userlist, $context, 'tool_mobile');
|
||||
\core_userkey\privacy\provider::get_user_contexts_with_script($userlist, $context, 'tool_mobile/qrlogin');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,6 +109,7 @@ class provider implements
|
||||
}
|
||||
// Export associated userkeys.
|
||||
\core_userkey\privacy\provider::export_userkeys($context, [], 'tool_mobile');
|
||||
\core_userkey\privacy\provider::export_userkeys($context, [], 'tool_mobile/qrlogin');
|
||||
}
|
||||
/**
|
||||
* Export all user preferences for the plugin.
|
||||
@@ -138,6 +140,7 @@ class provider implements
|
||||
$userid = $context->instanceid;
|
||||
// Delete all the userkeys.
|
||||
\core_userkey\privacy\provider::delete_userkeys('tool_mobile', $userid);
|
||||
\core_userkey\privacy\provider::delete_userkeys('tool_mobile/qrlogin', $userid);
|
||||
}
|
||||
/**
|
||||
* Delete all user data for the specified user, in the specified contexts.
|
||||
@@ -158,6 +161,7 @@ class provider implements
|
||||
$userid = $context->instanceid;
|
||||
// Delete all the userkeys.
|
||||
\core_userkey\privacy\provider::delete_userkeys('tool_mobile', $userid);
|
||||
\core_userkey\privacy\provider::delete_userkeys('tool_mobile/qrlogin', $userid);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,5 +182,6 @@ class provider implements
|
||||
|
||||
// Delete all the userkeys.
|
||||
\core_userkey\privacy\provider::delete_userkeys('tool_mobile', $userid);
|
||||
\core_userkey\privacy\provider::delete_userkeys('tool_mobile/qrlogin', $userid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,14 @@ if (empty($service)) {
|
||||
throw new moodle_exception('servicenotavailable', 'webservice');
|
||||
}
|
||||
|
||||
// If the user is using the inapp (embedded) browser, we need to set the Secure and Partitioned attributes to the session cookie.
|
||||
if (\core_useragent::is_moodle_app()) {
|
||||
\core\session\utility\cookie_helper::add_attributes_to_cookie_response_header(
|
||||
"MoodleSession{$CFG->sessioncookie}",
|
||||
['Secure', 'Partitioned'],
|
||||
);
|
||||
}
|
||||
|
||||
require_login(0, false);
|
||||
|
||||
// Require an active user: not guest, not suspended.
|
||||
|
||||
@@ -87,7 +87,8 @@ class provider_test extends \core_privacy\tests\provider_testcase {
|
||||
$context1 = \context_user::instance($user1->id);
|
||||
$context2 = \context_user::instance($user2->id);
|
||||
$key1 = get_user_key('tool_mobile', $user1->id);
|
||||
$key2 = get_user_key('tool_mobile', $user2->id);
|
||||
$key2 = get_user_key('tool_mobile/qrlogin', $user1->id);
|
||||
$key3 = get_user_key('tool_mobile', $user2->id);
|
||||
|
||||
// Ensure only user1 is found in context1.
|
||||
$userlist = new \core_privacy\local\request\userlist($context1, $component);
|
||||
@@ -174,12 +175,15 @@ class provider_test extends \core_privacy\tests\provider_testcase {
|
||||
$context1 = \context_user::instance($user1->id);
|
||||
$context2 = \context_user::instance($user2->id);
|
||||
$keyvalue1 = get_user_key('tool_mobile', $user1->id);
|
||||
$keyvalue2 = get_user_key('tool_mobile', $user2->id);
|
||||
$keyvalue2 = get_user_key('tool_mobile/qrlogin', $user1->id);
|
||||
$keyvalue3 = get_user_key('tool_mobile', $user2->id);
|
||||
$key1 = $DB->get_record('user_private_key', ['value' => $keyvalue1]);
|
||||
|
||||
// Before deletion, we should have 2 user_private_keys.
|
||||
// Before deletion, we should have 2 user_private_keys for tool_mobile and one for tool_mobile/qrlogin.
|
||||
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']);
|
||||
$this->assertEquals(2, $count);
|
||||
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile/qrlogin']);
|
||||
$this->assertEquals(1, $count);
|
||||
|
||||
// Ensure deleting wrong user in the user context does nothing.
|
||||
$approveduserids = [$user2->id];
|
||||
@@ -197,6 +201,8 @@ class provider_test extends \core_privacy\tests\provider_testcase {
|
||||
// Ensure only user1's data is deleted, user2's remains.
|
||||
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']);
|
||||
$this->assertEquals(1, $count);
|
||||
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile/qrlogin']);
|
||||
$this->assertEquals(0, $count);
|
||||
|
||||
$params = ['script' => $component];
|
||||
$userid = $DB->get_field_select('user_private_key', 'userid', 'script = :script', $params);
|
||||
|
||||
@@ -63,7 +63,7 @@ if ($cancel) {
|
||||
}
|
||||
redirect($url);
|
||||
} else if ($continue) {
|
||||
confirm_sesskey();
|
||||
require_sesskey();
|
||||
|
||||
// Handle backups.
|
||||
if (strtolower($importinfo->get_resource()->get_extension()) == 'mbz') {
|
||||
|
||||
@@ -81,7 +81,7 @@ switch ($config->type) {
|
||||
}
|
||||
|
||||
if ($import && $module) {
|
||||
confirm_sesskey();
|
||||
require_sesskey();
|
||||
|
||||
$handlerinfo = $handlerregistry->get_resource_handler_for_mod_and_strategy($importinfo->get_resource(), $module, $strategy);
|
||||
if (is_null($handlerinfo)) {
|
||||
|
||||
@@ -170,6 +170,7 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
|
||||
And I navigate to "Users > Privacy and policies > Manage policies" in site administration
|
||||
And I click on "Actions" "link_or_button" in the "This privacy policy" "table_row"
|
||||
And I click on "Set status to \"Active\"" "link" in the "This privacy policy" "table_row"
|
||||
And I wait until "Activate" "button" exists
|
||||
And I press "Activate"
|
||||
And I log out
|
||||
When I log in as "manager"
|
||||
@@ -260,6 +261,7 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
|
||||
And I navigate to "Users > Privacy and policies > Manage policies" in site administration
|
||||
And I click on "Actions" "link_or_button" in the "This privacy policy" "table_row"
|
||||
And I click on "Set status to \"Active\"" "link" in the "This privacy policy" "table_row"
|
||||
And I wait until "Activate" "button" exists
|
||||
And I press "Activate"
|
||||
And I log out
|
||||
When I log in as "manager"
|
||||
|
||||
@@ -62,8 +62,8 @@ Feature: Manage scheduled tasks
|
||||
And I press "Save changes"
|
||||
Then I should see "Changes saved"
|
||||
And the following should not exist in the "admintable" table:
|
||||
| Name | Component | Minute | Hour | Day | Day of week | Month |
|
||||
| Log table cleanup | Standard log | */5 | 1 | 2 | 4 | 3 |
|
||||
| Name | Minute | Hour | Day | Day of week | Month |
|
||||
| Log table cleanup | */5 | 1 | 2 | 4 | 3 |
|
||||
And I should see "Log table cleanup" in the "tr.table-primary" "css_element"
|
||||
|
||||
Scenario: Disabled plugin's tasks are labelled as disabled too
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -36,6 +36,7 @@ import {dispatchEvent} from 'core/event_dispatcher';
|
||||
import {eventTypes} from './events';
|
||||
import {get_string as getString} from 'core/str';
|
||||
import {prefetchStrings} from 'core/prefetch';
|
||||
import PendingPromise from 'core/pending';
|
||||
|
||||
/**
|
||||
* The minimum spacing for tour step to display.
|
||||
@@ -485,14 +486,22 @@ const Tour = class {
|
||||
return this.endTour();
|
||||
}
|
||||
|
||||
const pendingPromise = new PendingPromise(`tool_usertours/tour:_gotoStep-${stepConfig.stepNumber}`);
|
||||
|
||||
if (typeof stepConfig.delay !== 'undefined' && stepConfig.delay && !stepConfig.delayed) {
|
||||
stepConfig.delayed = true;
|
||||
window.setTimeout(this._gotoStep.bind(this), stepConfig.delay, stepConfig, direction);
|
||||
window.setTimeout(function(stepConfig, direction) {
|
||||
this._gotoStep(stepConfig, direction);
|
||||
pendingPromise.resolve();
|
||||
}, stepConfig.delay, stepConfig, direction);
|
||||
|
||||
return this;
|
||||
} else if (!stepConfig.orphan && !this.isStepActuallyVisible(stepConfig)) {
|
||||
let fn = direction == -1 ? 'getPreviousStepNumber' : 'getNextStepNumber';
|
||||
return this.gotoStep(this[fn](stepConfig.stepNumber), direction);
|
||||
const fn = direction == -1 ? 'getPreviousStepNumber' : 'getNextStepNumber';
|
||||
this.gotoStep(this[fn](stepConfig.stepNumber), direction);
|
||||
|
||||
pendingPromise.resolve();
|
||||
return this;
|
||||
}
|
||||
|
||||
this.hide();
|
||||
@@ -503,6 +512,7 @@ const Tour = class {
|
||||
this.dispatchEvent(eventTypes.stepRendered, {stepConfig});
|
||||
}
|
||||
|
||||
pendingPromise.resolve();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -820,12 +830,14 @@ const Tour = class {
|
||||
left: 0,
|
||||
});
|
||||
|
||||
const pendingPromise = new PendingPromise(`tool_usertours/tour:addStepToPage-${stepConfig.stepNumber}`);
|
||||
animationTarget
|
||||
.animate({
|
||||
scrollTop: this.calculateScrollTop(stepConfig),
|
||||
}).promise().then(function() {
|
||||
this.positionStep(stepConfig);
|
||||
this.revealStep(stepConfig);
|
||||
pendingPromise.resolve();
|
||||
return;
|
||||
}.bind(this))
|
||||
.catch(function() {
|
||||
@@ -897,6 +909,7 @@ const Tour = class {
|
||||
*/
|
||||
revealStep(stepConfig) {
|
||||
// Fade the step in.
|
||||
const pendingPromise = new PendingPromise(`tool_usertours/tour:revealStep-${stepConfig.stepNumber}`);
|
||||
this.currentStepNode.fadeIn('', $.proxy(function() {
|
||||
// Announce via ARIA.
|
||||
this.announceStep(stepConfig);
|
||||
@@ -910,6 +923,7 @@ const Tour = class {
|
||||
if (this.currentStepNode) {
|
||||
this.currentStepNode.focus();
|
||||
}
|
||||
pendingPromise.resolve();
|
||||
}, this), 100);
|
||||
|
||||
}, this));
|
||||
@@ -1157,6 +1171,7 @@ const Tour = class {
|
||||
return this;
|
||||
}
|
||||
|
||||
const pendingPromise = new PendingPromise('tool_usertours/tour:hide');
|
||||
if (this.currentStepNode && this.currentStepNode.length) {
|
||||
this.currentStepNode.hide();
|
||||
if (this.currentStepPopper) {
|
||||
@@ -1191,17 +1206,22 @@ const Tour = class {
|
||||
this.currentStepConfig = null;
|
||||
}
|
||||
|
||||
let fadeTime = 0;
|
||||
if (transition) {
|
||||
fadeTime = 400;
|
||||
}
|
||||
|
||||
// Remove the backdrop features.
|
||||
$('[data-flexitour="step-background"]').remove();
|
||||
$('[data-flexitour="step-backdrop"]').removeAttr('data-flexitour');
|
||||
$('[data-flexitour="backdrop"]').fadeOut(fadeTime, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
const backdrop = $('[data-flexitour="backdrop"]');
|
||||
if (backdrop.length) {
|
||||
if (transition) {
|
||||
const backdropRemovalPromise = new PendingPromise('tool_usertours/tour:hide:backdrop');
|
||||
backdrop.fadeOut(400, function() {
|
||||
$(this).remove();
|
||||
backdropRemovalPromise.resolve();
|
||||
});
|
||||
} else {
|
||||
backdrop.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove aria-describedby and tabindex attributes.
|
||||
if (this.currentStepNode && this.currentStepNode.length) {
|
||||
@@ -1222,6 +1242,8 @@ const Tour = class {
|
||||
|
||||
this.currentStepNode = null;
|
||||
this.currentStepPopper = null;
|
||||
|
||||
pendingPromise.resolve();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@ class new_table_from_mysql extends XMLDBAction {
|
||||
function init() {
|
||||
parent::init();
|
||||
|
||||
global $DB;
|
||||
if ($DB->get_dbfamily() !== 'mysql') {
|
||||
throw new moodle_exception('DB family not supported');
|
||||
}
|
||||
|
||||
// Set own custom attributes
|
||||
|
||||
// Get needed strings
|
||||
@@ -55,8 +60,6 @@ class new_table_from_mysql extends XMLDBAction {
|
||||
function invoke() {
|
||||
parent::invoke();
|
||||
|
||||
$result = true;
|
||||
|
||||
// Set own core attributes
|
||||
$this->does_generate = ACTION_GENERATE_HTML;
|
||||
|
||||
@@ -125,11 +128,15 @@ class new_table_from_mysql extends XMLDBAction {
|
||||
// If table, retrofit information and, if everything works,
|
||||
// go to the table edit action
|
||||
} else {
|
||||
// Get some params (table is mandatory here)
|
||||
$tableparam = required_param('table', PARAM_CLEAN);
|
||||
$afterparam = required_param('after', PARAM_CLEAN);
|
||||
// Get some params (table is mandatory here).
|
||||
$tableparam = required_param('table', PARAM_ALPHANUMEXT);
|
||||
$afterparam = required_param('after', PARAM_ALPHANUMEXT);
|
||||
|
||||
// Create one new xmldb_table
|
||||
if (empty($tableparam) || empty($afterparam)) {
|
||||
throw new moodle_exception('Invalid param value detected.');
|
||||
}
|
||||
|
||||
// Create one new xmldb_table.
|
||||
$table = new xmldb_table(strtolower(trim($tableparam)));
|
||||
$table->setComment($table->getName() . ' table retrofitted from MySQL');
|
||||
// Get fields info from ADODb
|
||||
@@ -147,7 +154,6 @@ class new_table_from_mysql extends XMLDBAction {
|
||||
// Get PK, UK and indexes info from ADODb
|
||||
$dbindexes = $DB->get_indexes($tableparam);
|
||||
if ($dbindexes) {
|
||||
$lastkey = NULL; //To temp store the last key processed
|
||||
foreach ($dbindexes as $indexname => $dbindex) {
|
||||
// Add the indexname to the array
|
||||
$dbindex['name'] = $indexname;
|
||||
@@ -156,9 +162,6 @@ class new_table_from_mysql extends XMLDBAction {
|
||||
$key = new xmldb_key(strtolower($dbindex['name']));
|
||||
// Set key with info retrofitted
|
||||
$key->setFromADOKey($dbindex);
|
||||
// Set default comment to PKs
|
||||
if ($key->getType() == XMLDB_KEY_PRIMARY) {
|
||||
}
|
||||
// Add key to the table
|
||||
$table->addKey($key);
|
||||
|
||||
@@ -172,18 +175,17 @@ class new_table_from_mysql extends XMLDBAction {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally, add the whole retroffited table to the structure
|
||||
// in the place specified
|
||||
// Finally, add the whole retrofitted table to the structure in the place specified.
|
||||
$structure->addTable($table, $afterparam);
|
||||
}
|
||||
|
||||
// Launch postaction if exists (leave this here!)
|
||||
if ($this->getPostAction() && $result) {
|
||||
if ($this->getPostAction()) {
|
||||
return $this->launch($this->getPostAction());
|
||||
}
|
||||
|
||||
// Return ok if arrived here
|
||||
return $result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,6 +114,7 @@ Feature: Manage analytics models
|
||||
And I should see "Read actions amount"
|
||||
And I click on "Select Student 6 for bulk action" "checkbox" in the "Student 6" "table_row"
|
||||
And I click on "Accept" "button"
|
||||
And I wait until "Confirm" "button" exists
|
||||
And I click on "Confirm" "button" in the "Accept" "dialogue"
|
||||
And I click on "View prediction details" "icon" in the "Student 5" "table_row"
|
||||
And I click on "Select Student 5 for bulk action" "checkbox" in the "Student 5" "table_row"
|
||||
@@ -145,7 +146,8 @@ Feature: Manage analytics models
|
||||
When I open the action menu in "Students at risk of not meeting the course completion conditions" "table_row"
|
||||
And I choose "Export" in the open action menu
|
||||
And I click on "Actions" "link" in the "Students at risk of not meeting the course completion conditions" "table_row"
|
||||
And following "Export" should download between "100" and "500" bytes
|
||||
And following "Export" should download a file that:
|
||||
| Contains file in zip | model-config.json |
|
||||
|
||||
Scenario: Check invalid site elements
|
||||
When I open the action menu in "Students at risk of not meeting the course completion conditions" "table_row"
|
||||
|
||||
+9
-11
@@ -14,31 +14,29 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for activities completed by classification.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_analytics;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
use advanced_testcase;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Unit tests for activities completed by classification.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @covers \core_analytics\local\indicator\community_of_inquiry_activity
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class community_of_inquiry_activities_completed_by_testcase extends advanced_testcase {
|
||||
final class community_of_inquiry_activities_completed_by_test extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* availability_levels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function availability_levels() {
|
||||
public static function availability_levels(): array {
|
||||
return array(
|
||||
'activity' => array('activity'),
|
||||
'section' => array('section'),
|
||||
@@ -148,7 +146,7 @@ class community_of_inquiry_activities_completed_by_testcase extends advanced_tes
|
||||
$second = $startdate + WEEKSECS;
|
||||
$third = $startdate + (WEEKSECS * 2);
|
||||
$forth = $startdate + (WEEKSECS * 3);
|
||||
$this->assertCount(1, $method->invoke($indicator, $first, $first + WEEKSECS, $stu1));
|
||||
$this->assertCount(2, $method->invoke($indicator, $first, $first + WEEKSECS, $stu1));
|
||||
$this->assertCount(1, $method->invoke($indicator, $second, $second + WEEKSECS, $stu1));
|
||||
$this->assertCount(0, $method->invoke($indicator, $third, $third + WEEKSECS, $stu1));
|
||||
$this->assertCount(2, $method->invoke($indicator, $forth, $forth + WEEKSECS, $stu1));
|
||||
@@ -345,7 +345,7 @@ class api {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete linked login
|
||||
* Delete a users own linked login
|
||||
*
|
||||
* Requires auth/oauth2:managelinkedlogins capability at the user context.
|
||||
*
|
||||
@@ -353,14 +353,19 @@ class api {
|
||||
* @return boolean
|
||||
*/
|
||||
public static function delete_linked_login($linkedloginid) {
|
||||
$login = new linked_login($linkedloginid);
|
||||
$userid = $login->get('userid');
|
||||
global $USER;
|
||||
|
||||
if (\core\session\manager::is_loggedinas()) {
|
||||
throw new moodle_exception('notwhileloggedinas', 'auth_oauth2');
|
||||
}
|
||||
|
||||
$context = context_user::instance($userid);
|
||||
$login = linked_login::get_record([
|
||||
'id' => $linkedloginid,
|
||||
'userid' => $USER->id,
|
||||
'confirmtoken' => '',
|
||||
], MUST_EXIST);
|
||||
|
||||
$context = context_user::instance($login->get('userid'));
|
||||
require_capability('auth/oauth2:managelinkedlogins', $context);
|
||||
|
||||
$login->delete();
|
||||
|
||||
@@ -137,6 +137,7 @@ class api_test extends \advanced_testcase {
|
||||
$issuer = \core\oauth2\api::create_standard_issuer('google');
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->setUser($user);
|
||||
|
||||
$info = [];
|
||||
$info['username'] = 'banana';
|
||||
@@ -169,6 +170,30 @@ class api_test extends \advanced_testcase {
|
||||
$this->assertEquals($newuser->id, $match->get('userid'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we cannot deleted a linked login for another user
|
||||
*/
|
||||
public function test_delete_linked_login_other_user(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->setAdminUser();
|
||||
$issuer = \core\oauth2\api::create_standard_issuer('google');
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
|
||||
api::link_login([
|
||||
'username' => 'banana',
|
||||
'email' => 'banana@example.com',
|
||||
], $issuer, $user->id);
|
||||
|
||||
/** @var linked_login $linkedlogin */
|
||||
$linkedlogin = api::get_linked_logins($user->id)[0];
|
||||
|
||||
// We are logged in as a different user, so cannot delete this.
|
||||
$this->expectException(\dml_missing_record_exception::class);
|
||||
api::delete_linked_login($linkedlogin->get('id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that is_enabled correctly identifies when the plugin is enabled.
|
||||
*/
|
||||
|
||||
@@ -52,7 +52,7 @@ abstract class backup_block_task extends backup_task {
|
||||
}
|
||||
|
||||
$this->blockid = $blockid;
|
||||
$this->blockname = $block->blockname;
|
||||
$this->blockname = clean_param($block->blockname, PARAM_PLUGIN);
|
||||
$this->contextid = context_block::instance($this->blockid)->id;
|
||||
$this->moduleid = $moduleid;
|
||||
$this->modulename = null;
|
||||
|
||||
+10
-10
@@ -134,14 +134,14 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
$html .= $this->backup_detail_pair(get_string('backupmode', 'backup'), get_string('backupmode'.$details->mode, 'backup'));
|
||||
$html .= $this->backup_detail_pair(get_string('backupdate', 'backup'), userdate($details->backup_date));
|
||||
$html .= $this->backup_detail_pair(get_string('moodleversion', 'backup'),
|
||||
html_writer::tag('span', $details->moodle_release, array('class' => 'moodle_release')).
|
||||
html_writer::tag('span', '['.$details->moodle_version.']', array('class' => 'moodle_version sub-detail')));
|
||||
html_writer::tag('span', s($details->moodle_release), array('class' => 'moodle_release')).
|
||||
html_writer::tag('span', '[' . s($details->moodle_version) .']', array('class' => 'moodle_version sub-detail')));
|
||||
$html .= $this->backup_detail_pair(get_string('backupversion', 'backup'),
|
||||
html_writer::tag('span', $details->backup_release, array('class' => 'moodle_release')).
|
||||
html_writer::tag('span', '['.$details->backup_version.']', array('class' => 'moodle_version sub-detail')));
|
||||
html_writer::tag('span', s($details->backup_release), array('class' => 'moodle_release')).
|
||||
html_writer::tag('span', '[' . s($details->backup_version) . ']', array('class' => 'moodle_version sub-detail')));
|
||||
$html .= $this->backup_detail_pair(get_string('originalwwwroot', 'backup'),
|
||||
html_writer::tag('span', $details->original_wwwroot, array('class' => 'originalwwwroot')).
|
||||
html_writer::tag('span', '['.$details->original_site_identifier_hash.']', array('class' => 'sitehash sub-detail')));
|
||||
html_writer::tag('span', s($details->original_wwwroot), array('class' => 'originalwwwroot')).
|
||||
html_writer::tag('span', '[' . s($details->original_site_identifier_hash) . ']', array('class' => 'sitehash sub-detail')));
|
||||
if (!empty($details->include_file_references_to_external_content)) {
|
||||
$message = '';
|
||||
if (backup_general_helper::backup_is_samesite($details)) {
|
||||
@@ -169,8 +169,8 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
$html .= html_writer::start_tag('div', ['class' => 'backup-section',
|
||||
'role' => 'table', 'aria-labelledby' => 'backupcoursedetailsheader']);
|
||||
$html .= $this->output->heading(get_string('backupcoursedetails', 'backup'), 2, 'header', 'backupcoursedetailsheader');
|
||||
$html .= $this->backup_detail_pair(get_string('coursetitle', 'backup'), $details->course->title);
|
||||
$html .= $this->backup_detail_pair(get_string('courseid', 'backup'), $details->course->courseid);
|
||||
$html .= $this->backup_detail_pair(get_string('coursetitle', 'backup'), format_string($details->course->title));
|
||||
$html .= $this->backup_detail_pair(get_string('courseid', 'backup'), clean_param($details->course->courseid, PARAM_INT));
|
||||
|
||||
// Warning users about front page backups.
|
||||
if ($details->original_course_format === 'site') {
|
||||
@@ -188,7 +188,7 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
$html .= $this->backup_detail_pair(get_string('backupcoursesection', 'backup', $section->title), $value);
|
||||
$html .= $this->backup_detail_pair(get_string('backupcoursesection', 'backup', format_string($section->title)), $value);
|
||||
$table = null;
|
||||
foreach ($details->activities as $activitykey => $activity) {
|
||||
if ($activity->sectionid != $section->sectionid) {
|
||||
@@ -206,7 +206,7 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
$icon = new image_icon('monologo', '', $activity->modulename, ['class' => 'iconlarge icon-pre']);
|
||||
$table->data[] = array(
|
||||
$this->output->render($icon).$name,
|
||||
$activity->title,
|
||||
format_string($activity->title),
|
||||
($activity->settings[$activitykey.'_userinfo']) ? $yestick : $notick,
|
||||
);
|
||||
}
|
||||
|
||||
+2
-1
@@ -107,9 +107,10 @@ if (!has_any_capability(array(
|
||||
$PAGE->set_title($hdr);
|
||||
$output = $PAGE->get_renderer('core', 'badges');
|
||||
|
||||
if (($delete || $archive) && has_capability('moodle/badges:deletebadge', $PAGE->context)) {
|
||||
if ($delete || $archive) {
|
||||
$badgeid = ($archive != 0) ? $archive : $delete;
|
||||
$badge = new badge($badgeid);
|
||||
require_capability('moodle/badges:deletebadge', $badge->get_context());
|
||||
if (!$confirm) {
|
||||
echo $output->header();
|
||||
// Archive this badge?
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
.block_accessreview_success,
|
||||
.block_accessreview.block_accessreview_success.hasinfo {
|
||||
color: #1e451e;
|
||||
background: #d7e6d7;
|
||||
border-color: #c8ddc8;
|
||||
background: #eff5ef;
|
||||
box-shadow: 0 0 2px 2px #619a61;
|
||||
}
|
||||
|
||||
.block_accessreview_danger,
|
||||
.block_accessreview.block_accessreview_danger.hasinfo {
|
||||
color: #6e211e;
|
||||
background: #f6d9d8;
|
||||
border-color: #f3c9c8;
|
||||
background: #fdf7f7;
|
||||
box-shadow: 0 0 2px 2px #da6960;
|
||||
}
|
||||
|
||||
.block_accessreview_warning,
|
||||
.block_accessreview.block_accessreview_warning.hasinfo {
|
||||
color: #7d5a29;
|
||||
background: #fcefdc;
|
||||
border-color: #fbe8cd;
|
||||
color: #694b21;
|
||||
background: #fdf2e3;
|
||||
box-shadow: 0 0 2px 2px #c97a0e;
|
||||
}
|
||||
|
||||
.block_accessreview_table {
|
||||
|
||||
@@ -58,7 +58,7 @@ class helper {
|
||||
FROM {block_recentlyaccesseditems} rai
|
||||
JOIN {course} c ON c.id = rai.courseid
|
||||
WHERE userid = :userid
|
||||
ORDER BY rai.timeaccess DESC";
|
||||
ORDER BY rai.timeaccess DESC, rai.id DESC";
|
||||
$records = $DB->get_records_sql($sql, $paramsql);
|
||||
$order = 0;
|
||||
|
||||
|
||||
@@ -27,9 +27,8 @@
|
||||
<div class="text-xs-center text-center mt-4" data-region="empty-message">
|
||||
<img
|
||||
src="{{noitemsimgurl}}"
|
||||
alt="{{#str}} noitems, block_recentlyaccesseditems {{/str}}"
|
||||
role="presentation"
|
||||
alt=""
|
||||
style="height: 70px; width: 70px;"
|
||||
>
|
||||
<p class="text-muted mt-3 mb-0">{{#str}} noitems, block_recentlyaccesseditems {{/str}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -180,7 +180,18 @@ $PAGE->set_pagelayout('admin');
|
||||
|
||||
if ($rssid) {
|
||||
$isadding = false;
|
||||
$rssrecord = $DB->get_record('block_rss_client', array('id' => $rssid), '*', MUST_EXIST);
|
||||
|
||||
if ($managesharedfeeds) {
|
||||
$select = 'id = :id AND (userid = :userid OR shared = 1)';
|
||||
} else {
|
||||
$select = 'id = :id AND userid = :userid';
|
||||
}
|
||||
|
||||
$rssrecord = $DB->get_record_select('block_rss_client', $select, [
|
||||
'id' => $rssid,
|
||||
'userid' => $USER->id,
|
||||
], '*', MUST_EXIST);
|
||||
|
||||
} else {
|
||||
$isadding = true;
|
||||
$rssrecord = new stdClass;
|
||||
|
||||
@@ -61,20 +61,27 @@ if ($returnurl) {
|
||||
$baseurl = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams);
|
||||
$PAGE->set_url($baseurl);
|
||||
|
||||
if ($managesharedfeeds) {
|
||||
$select = '(userid = :userid OR shared = 1)';
|
||||
} else {
|
||||
$select = 'userid = :userid';
|
||||
}
|
||||
|
||||
// Process any actions
|
||||
if ($deleterssid && confirm_sesskey()) {
|
||||
$DB->delete_records('block_rss_client', array('id'=>$deleterssid));
|
||||
|
||||
$deleterssid = $DB->get_field_select('block_rss_client', 'id', "id = :id AND {$select}", [
|
||||
'id' => $deleterssid,
|
||||
'userid' => $USER->id
|
||||
], MUST_EXIST);
|
||||
|
||||
$DB->delete_records('block_rss_client', ['id' => $deleterssid]);
|
||||
|
||||
redirect($PAGE->url, get_string('feeddeleted', 'block_rss_client'));
|
||||
}
|
||||
|
||||
// Display the list of feeds.
|
||||
if ($managesharedfeeds) {
|
||||
$select = '(userid = ' . $USER->id . ' OR shared = 1)';
|
||||
} else {
|
||||
$select = 'userid = ' . $USER->id;
|
||||
}
|
||||
$feeds = $DB->get_records_select('block_rss_client', $select, null, $DB->sql_order_by_text('title'));
|
||||
$feeds = $DB->get_records_select('block_rss_client', $select, ['userid' => $USER->id], $DB->sql_order_by_text('title'));
|
||||
|
||||
$strmanage = get_string('managefeeds', 'block_rss_client');
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Feature: Edit activities in main menu block
|
||||
I need to add and edit activities there
|
||||
|
||||
@javascript
|
||||
Scenario: Edit name of acitivity in-place in site main menu block
|
||||
Scenario: Edit name of activity in-place in site main menu block
|
||||
Given the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | Acceptance test site |
|
||||
@@ -36,6 +36,7 @@ Feature: Edit activities in main menu block
|
||||
| forum | Acceptance test site | 0 | Visible forum |
|
||||
| forum | Acceptance test site | 0 | My forum name |
|
||||
And I log in as "admin"
|
||||
And I change window size to "large"
|
||||
And I am on site homepage
|
||||
And I turn editing mode on
|
||||
And "My forum name" activity in site main menu block should have "Hide" editing icon
|
||||
|
||||
@@ -3555,6 +3555,18 @@ function calendar_get_view(\calendar_information $calendar, $view, $includenavig
|
||||
}
|
||||
}
|
||||
|
||||
// Check if $data has events.
|
||||
if (isset($data->events)) {
|
||||
// Let's check and sanitize all "name" in $data->events before it's sent to front end.
|
||||
foreach ($data->events as $d) {
|
||||
$name = $d->name ?? null;
|
||||
// Encode special characters if our decoded name does not match the original name.
|
||||
if ($name && (html_entity_decode($name) !== $name)) {
|
||||
$d->name = htmlspecialchars(html_entity_decode($name), ENT_QUOTES, 'utf-8');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [$data, $template];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
@core @core_contentbank @core_h5p @contenttype_h5p @_file_upload @_switch_iframe @javascript
|
||||
@core @core_contentbank @core_h5p @contenttype_h5p @_switch_iframe @javascript
|
||||
Feature: H5P file upload to content bank for admins
|
||||
In order import new H5P content to content bank
|
||||
As an admin
|
||||
I need to be able to upload a new .h5p file to content bank
|
||||
|
||||
Background:
|
||||
Given the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| private_files | System | 1 | my-index | side-post |
|
||||
Given the following "user private file" exists:
|
||||
| user | admin |
|
||||
| filepath | h5p/tests/fixtures/filltheblanks.h5p |
|
||||
And I log in as "admin"
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
And I turn editing mode on
|
||||
And the following config values are set as admin:
|
||||
| unaddableblocks | | theme_boost|
|
||||
|
||||
@@ -19,13 +19,10 @@ Feature: H5P file upload to content bank for non admins
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| teacher2 | C1 | editingteacher |
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| private_files | System | 1 | my-index | side-post |
|
||||
And the following "user private file" exists:
|
||||
| user | teacher1 |
|
||||
| filepath | h5p/tests/fixtures/filltheblanks.h5p |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
|
||||
Scenario: Teachers can not access system level content bank
|
||||
Given I turn editing mode on
|
||||
@@ -128,11 +125,10 @@ Feature: H5P file upload to content bank for non admins
|
||||
And I should not see "filltheblanks.h5p"
|
||||
|
||||
Scenario: Teachers can not see existing contents when libraries are not installed
|
||||
Given I log out
|
||||
Given the following "user private file" exists:
|
||||
| user | admin |
|
||||
| filepath | h5p/tests/fixtures/filltheblanks.h5p |
|
||||
And I log in as "admin"
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
And I navigate to "H5P > Manage H5P content types" in site administration
|
||||
And I should not see "Fill in the Blanks"
|
||||
When I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
|
||||
|
||||
@@ -1,28 +1,14 @@
|
||||
@core @core_contentbank @core_h5p @contentbank_h5p @_file_upload @javascript
|
||||
@core @core_contentbank @core_h5p @contentbank_h5p @javascript
|
||||
Feature: Delete H5P file from the content bank
|
||||
In order remove H5P content from the content bank
|
||||
As an admin
|
||||
I need to be able to delete any H5P content from the content bank
|
||||
|
||||
Background:
|
||||
Given the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| private_files | System | 1 | my-index | side-post |
|
||||
And I log in as "admin"
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
And I am on site homepage
|
||||
And I turn editing mode on
|
||||
And the following config values are set as admin:
|
||||
| unaddableblocks | | theme_boost|
|
||||
And I add the "Navigation" block if not present
|
||||
And I configure the "Navigation" block
|
||||
And I set the following fields to these values:
|
||||
| Page contexts | Display throughout the entire site |
|
||||
And I press "Save changes"
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
Given the following "user private file" exists:
|
||||
| user | admin |
|
||||
| filepath | h5p/tests/fixtures/filltheblanks.h5p |
|
||||
And I am on the "Content bank" page logged in as "admin"
|
||||
And I click on "Upload" "link"
|
||||
And I click on "Choose a file..." "button"
|
||||
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
|
||||
@@ -32,14 +18,16 @@ Feature: Delete H5P file from the content bank
|
||||
And I click on "Save changes" "button"
|
||||
|
||||
Scenario: Admins can delete content from the content bank
|
||||
Given I click on "More" "button"
|
||||
Given I wait "2" seconds
|
||||
And I click on "More" "button"
|
||||
And I should see "Delete"
|
||||
And I click on "Delete" "link" in the ".cb-toolbar-container" "css_element"
|
||||
And I click on "Delete" "link"
|
||||
And I should see "Are you sure you want to delete the content 'content2delete.h5p'"
|
||||
And I should not see "The content will only be deleted from the content bank"
|
||||
And I click on "Cancel" "button" in the "Delete content" "dialogue"
|
||||
Then I should see "content2delete.h5p"
|
||||
And I click on "More" "button"
|
||||
And I wait "2" seconds
|
||||
And I click on "More" "button"
|
||||
And I click on "Delete" "link" in the ".cb-toolbar-container" "css_element"
|
||||
And I click on "Delete" "button" in the "Delete content" "dialogue"
|
||||
And I wait until the page is ready
|
||||
@@ -56,40 +44,38 @@ Feature: Delete H5P file from the content bank
|
||||
And the following "role assigns" exist:
|
||||
| user | role | contextlevel | reference |
|
||||
| manager | manager | System | |
|
||||
And I log out
|
||||
And I log in as "manager"
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/find-the-words.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
When I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And the following "user private file" exists:
|
||||
| user | manager |
|
||||
| filepath | h5p/tests/fixtures/find-the-words.h5p |
|
||||
When I am on the "Content bank" page logged in as "manager"
|
||||
And I should see "content2delete.h5p"
|
||||
And I follow "content2delete.h5p"
|
||||
And I wait "2" seconds
|
||||
And I click on "More" "button"
|
||||
Then I should not see "Delete"
|
||||
And I click on "Content bank" "link"
|
||||
And I am on the "Content bank" page
|
||||
And I click on "Upload" "link"
|
||||
And I click on "Choose a file..." "button"
|
||||
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
|
||||
And I click on "find-the-words.h5p" "link"
|
||||
And I click on "Select this file" "button"
|
||||
And I click on "Save changes" "button"
|
||||
And I click on "More" "button"
|
||||
And I wait "2" seconds
|
||||
And I click on "More" "button"
|
||||
And I should see "Delete"
|
||||
|
||||
Scenario: The number of times a content is used is displayed before removing it
|
||||
Given I follow "Dashboard"
|
||||
And I follow "Manage private files..."
|
||||
Given I am on the "My private files" page
|
||||
And I click on "Add..." "button"
|
||||
And I select "Content bank" repository in file picker
|
||||
And I click on "content2delete.h5p" "file" in repository content area
|
||||
And I click on "Link to the file" "radio"
|
||||
And I click on "Select this file" "button"
|
||||
And I click on "Save changes" "button"
|
||||
When I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And I am on the "Content bank" page
|
||||
And I follow "content2delete.h5p"
|
||||
And I click on "More" "button"
|
||||
And I wait "2" seconds
|
||||
And I click on "More" "button"
|
||||
And I click on "Delete" "link" in the ".cb-toolbar-container" "css_element"
|
||||
Then I should see "Are you sure you want to delete the content 'content2delete.h5p'"
|
||||
And I should see "The content will only be deleted from the content bank"
|
||||
|
||||
@@ -5,10 +5,7 @@ Feature: Content bank use editor feature
|
||||
I need to be able to access the edition options
|
||||
|
||||
Background:
|
||||
Given the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| private_files | System | 1 | my-index | side-post |
|
||||
And I log in as "admin"
|
||||
Given I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I turn editing mode on
|
||||
And the following config values are set as admin:
|
||||
@@ -25,10 +22,9 @@ Feature: Content bank use editor feature
|
||||
Then the "[data-action=Add-content]" "css_element" should be disabled
|
||||
|
||||
Scenario: Users can see the Add button if there is content type available for creation
|
||||
Given I follow "Dashboard"
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
Given the following "user private file" exists:
|
||||
| user | admin |
|
||||
| filepath | h5p/tests/fixtures/filltheblanks.h5p |
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And I click on "Upload" "link"
|
||||
@@ -44,10 +40,9 @@ Feature: Content bank use editor feature
|
||||
And I should see "Fill in the Blanks"
|
||||
|
||||
Scenario: Users can edit content if they have the required permission
|
||||
Given I follow "Dashboard"
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
Given the following "user private file" exists:
|
||||
| user | admin |
|
||||
| filepath | h5p/tests/fixtures/filltheblanks.h5p |
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And I click on "Upload" "link"
|
||||
|
||||
@@ -1,30 +1,23 @@
|
||||
@core @core_contentbank @core_h5p @contentbank_h5p @_file_upload @_switch_iframe @javascript
|
||||
@core @core_contentbank @core_h5p @contentbank_h5p @_switch_iframe @javascript
|
||||
Feature: Confirm content bank events are triggered
|
||||
In order to log content bank actions
|
||||
As an admin
|
||||
I need to be able to check triggered events
|
||||
|
||||
Background:
|
||||
Given the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| private_files | System | 1 | my-index | side-post |
|
||||
And I log in as "admin"
|
||||
And I navigate to "H5P > Manage H5P content types" in site administration
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
|
||||
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
|
||||
And the following "courses" exist:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "contentbank content" exist:
|
||||
| contextlevel | reference | contenttype | user | contentname | filepath |
|
||||
| Course | C1 | contenttype_h5p | admin | Existing | /h5p/tests/fixtures/filltheblanks.h5p |
|
||||
And I follow "Dashboard"
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And the following "user private file" exists:
|
||||
| user | admin |
|
||||
| filepath | h5p/tests/fixtures/filltheblanks.h5p |
|
||||
And the following config values are set as admin:
|
||||
| unaddableblocks | | theme_boost|
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Navigation" block if not present
|
||||
|
||||
Scenario: Content created and uploaded events when uploading a content file
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
@core @core_contentbank @core_h5p @contentbank_h5p @_file_upload @javascript
|
||||
@core @core_contentbank @core_h5p @contentbank_h5p @javascript
|
||||
Feature: Store the content bank view preference
|
||||
In order to consistantly view the content bank in icons or details view
|
||||
As an admin
|
||||
I need to be able to store my view preference
|
||||
|
||||
Background:
|
||||
Given the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| private_files | System | 1 | my-index | side-post |
|
||||
Given the following "user private files" exist:
|
||||
| user | filepath |
|
||||
| admin | h5p/tests/fixtures/filltheblanks.h5p |
|
||||
| admin | h5p/tests/fixtures/greeting-card.h5p |
|
||||
And I log in as "admin"
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Files" filemanager
|
||||
And I upload "h5p/tests/fixtures/greeting-card.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
And I am on site homepage
|
||||
And I turn editing mode on
|
||||
And the following config values are set as admin:
|
||||
@@ -55,8 +52,7 @@ Feature: Store the content bank view preference
|
||||
And I should not see "Last modified"
|
||||
|
||||
Scenario: Display the number of times a content is used in file details view
|
||||
Given I follow "Dashboard"
|
||||
And I follow "Manage private files..."
|
||||
Given I am on the "My private files" page
|
||||
And I click on "Add..." "button"
|
||||
And I select "Content bank" repository in file picker
|
||||
And I click on "fib.h5p" "file" in repository content area
|
||||
|
||||
@@ -46,7 +46,7 @@ $filename = str_replace('/', '', str_replace(' ', '_', $courseinfo->shortname))
|
||||
|
||||
// If download confirmed, prepare and start the zipstream of the course download content.
|
||||
if ($isdownload) {
|
||||
confirm_sesskey();
|
||||
require_sesskey();
|
||||
|
||||
$exportoptions = null;
|
||||
|
||||
|
||||
@@ -9,11 +9,13 @@ Feature: Display and choose from the available activities in course
|
||||
| username | firstname | lastname | email |
|
||||
| teacher | Teacher | 1 | teacher@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course | C | topics |
|
||||
| fullname | shortname | format | startdate |
|
||||
| Course | C | topics | |
|
||||
| Course 2 | C2 | weeks | 95713920 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher | C | editingteacher |
|
||||
| user | course | role |
|
||||
| teacher | C | editingteacher |
|
||||
| teacher | C2 | editingteacher |
|
||||
And the following config values are set as admin:
|
||||
| enablemoodlenet | 0 | tool_moodlenet |
|
||||
And I log in as "teacher"
|
||||
@@ -44,6 +46,12 @@ Feature: Display and choose from the available activities in course
|
||||
When I click on "Information about the Assignment activity" "button" in the "Add an activity or resource" "dialogue"
|
||||
Then I should see "Assignment" in the "help" "core_course > Activity chooser screen"
|
||||
And I should see "The assignment activity module enables a teacher to communicate tasks, collect work and provide grades and feedback."
|
||||
# Confirm show summary also works for weekly format course
|
||||
And I am on "C2" course homepage with editing mode on
|
||||
And I click on "Add an activity or resource" "button" in the "13 January - 19 January" "section"
|
||||
And I click on "Information about the Assignment activity" "button" in the "Add an activity or resource" "dialogue"
|
||||
And I should see "Assignment" in the "help" "core_course > Activity chooser screen"
|
||||
And I should see "The assignment activity module enables a teacher to communicate tasks, collect work and provide grades and feedback."
|
||||
|
||||
Scenario: Hide summary
|
||||
Given I click on "Add an activity or resource" "button" in the "Topic 1" "section"
|
||||
@@ -55,6 +63,15 @@ Feature: Display and choose from the available activities in course
|
||||
And "help" "core_course > Activity chooser screen" should not be visible
|
||||
And "Back" "button" should not exist in the "modules" "core_course > Activity chooser screen"
|
||||
And I should not see "The assignment activity module enables a teacher to communicate tasks, collect work and provide grades and feedback." in the "Add an activity or resource" "dialogue"
|
||||
# Confirm hide summary also works for weekly format course
|
||||
And I am on "C2" course homepage with editing mode on
|
||||
And I click on "Add an activity or resource" "button" in the "13 January - 19 January" "section"
|
||||
And I click on "Information about the Assignment activity" "button" in the "Add an activity or resource" "dialogue"
|
||||
And I click on "Back" "button" in the "help" "core_course > Activity chooser screen"
|
||||
And "modules" "core_course > Activity chooser screen" should be visible
|
||||
And "help" "core_course > Activity chooser screen" should not be visible
|
||||
And "Back" "button" should not exist in the "modules" "core_course > Activity chooser screen"
|
||||
And I should not see "The assignment activity module enables a teacher to communicate tasks, collect work and provide grades and feedback." in the "Add an activity or resource" "dialogue"
|
||||
|
||||
Scenario: View recommended activities
|
||||
When I log out
|
||||
@@ -189,3 +206,69 @@ Feature: Display and choose from the available activities in course
|
||||
Then I should not see "All" in the "Add an activity or resource" "dialogue"
|
||||
And I should see "Activities" in the "Add an activity or resource" "dialogue"
|
||||
And I should see "Resources" in the "Add an activity or resource" "dialogue"
|
||||
|
||||
Scenario: Teacher can navigate through activity chooser in Topics format course
|
||||
When I click on "Add an activity or resource" "button" in the "Topic 1" "section"
|
||||
Then I should see "All" in the "Add an activity or resource" "dialogue"
|
||||
And I press the tab key
|
||||
And I press the tab key
|
||||
And I press the tab key
|
||||
And I press the tab key
|
||||
# Confirm right key works
|
||||
And I press the right key
|
||||
And I press the right key
|
||||
And the focused element is "Chat" "menuitem" in the "Add an activity or resource" "dialogue"
|
||||
# Confirm left key works
|
||||
And I press the left key
|
||||
And the focused element is "Book" "menuitem" in the "Add an activity or resource" "dialogue"
|
||||
# Confirm clicking "x" button closes modal
|
||||
And I click on "Close" "button" in the "Add an activity or resource" "dialogue"
|
||||
And "Add an activity or resource" "dialogue" should not be visible
|
||||
And I click on "Add an activity or resource" "button" in the "Topic 1" "section"
|
||||
# Confirm escape key closes the modal
|
||||
And I press the escape key
|
||||
And "Add an activity or resource" "dialogue" should not be visible
|
||||
|
||||
Scenario: Teacher can navigate through activity chooser in Weekly format course
|
||||
Given I am on "C2" course homepage with editing mode on
|
||||
When I click on "Add an activity or resource" "button" in the "13 January - 19 January" "section"
|
||||
Then I should see "All" in the "Add an activity or resource" "dialogue"
|
||||
And I press the tab key
|
||||
And I press the tab key
|
||||
And I press the tab key
|
||||
And I press the tab key
|
||||
# Confirm right key works
|
||||
And I press the right key
|
||||
And I press the right key
|
||||
And the focused element is "Chat" "menuitem" in the "Add an activity or resource" "dialogue"
|
||||
# Confirm left key works
|
||||
And I press the left key
|
||||
And the focused element is "Book" "menuitem" in the "Add an activity or resource" "dialogue"
|
||||
# Confirm clicking "x" button closes modal
|
||||
And I click on "Close" "button" in the "Add an activity or resource" "dialogue"
|
||||
And "Add an activity or resource" "dialogue" should not be visible
|
||||
And I click on "Add an activity or resource" "button" in the "13 January - 19 January" "section"
|
||||
# Confirm escape key closes the modal
|
||||
And I press the escape key
|
||||
And "Add an activity or resource" "dialogue" should not be visible
|
||||
|
||||
Scenario: Teacher can access 'More help' from activity information in activity chooser
|
||||
Given I click on "Add an activity or resource" "button" in the "Topic 1" "section"
|
||||
When I click on "Information about the Assignment activity" "button" in the "Add an activity or resource" "dialogue"
|
||||
# Confirm more help link exists
|
||||
Then "More help" "link" should exist
|
||||
# Confirm that corresponding help icon exist
|
||||
And ".iconhelp" "css_element" should exist
|
||||
# Confirm that link opens in new window
|
||||
And "Opens in new window" "link" should be visible
|
||||
# Confirm the same behaviour for weekly format course
|
||||
And I am on "C2" course homepage with editing mode on
|
||||
And I click on "Add an activity or resource" "button" in the "13 January - 19 January" "section"
|
||||
And I should see "All" in the "Add an activity or resource" "dialogue"
|
||||
And I click on "Information about the Assignment activity" "button" in the "Add an activity or resource" "dialogue"
|
||||
# Confirm more help link exists
|
||||
And "More help" "link" should exist
|
||||
# Confirm that corresponding help icon exist
|
||||
And ".iconhelp" "css_element" should exist
|
||||
# Confirm that link opens in new window
|
||||
And "Opens in new window" "link" should be visible
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
@core @core_course @core_tag
|
||||
Feature: Delete activity tags during course reset
|
||||
As an admin,
|
||||
I should be able to delete activity tags by performing course reset
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber |
|
||||
| book | Test Book | C1 | book1 |
|
||||
| forum | Test Forum | C1 | forum1 |
|
||||
| glossary | Test Glossary | C1 | glossary1 |
|
||||
|
||||
@javascript
|
||||
Scenario: Delete book chapter tags using course reset
|
||||
# Added multiple tags to confirm that all tags are deleted on course reset.
|
||||
Given the following "mod_book > chapters" exist:
|
||||
| book | title | content | tags |
|
||||
| Test Book | Chapter 1 | Chapter 1 content | SampleTag, ChapterTag |
|
||||
# Perform course reset without checking anything.
|
||||
And I log in as "admin"
|
||||
And I am on the "Course 1" "reset" page
|
||||
And I press "Reset"
|
||||
And I press "Continue"
|
||||
# Confirm that book chapter tags are not deleted.
|
||||
When I am on the "Test Book" "book activity" page
|
||||
Then I should see "SampleTag"
|
||||
And I should see "ChapterTag"
|
||||
# Delete book chapter tags using course reset.
|
||||
And I am on the "Course 1" "reset" page
|
||||
And I expand all fieldsets
|
||||
And I click on "Remove all book tags" "checkbox"
|
||||
And I press "Reset"
|
||||
# Confirm that book chapter tags are deleted.
|
||||
And I should see "Book tags have been deleted" in the "Books" "table_row"
|
||||
And I press "Continue"
|
||||
And I am on the "Test Book" "book activity" page
|
||||
And I should not see "SampleTag"
|
||||
And I should not see "ChapterTag"
|
||||
|
||||
@javascript
|
||||
Scenario Outline: Delete forum discussion tags using course reset
|
||||
Given the following "mod_forum > discussions" exist:
|
||||
| user | forum | name | message | tags |
|
||||
| admin | forum1 | Discussion 1 | Discussion 1 message | SampleTag, DiscussionTag |
|
||||
# Perform course reset without checking anything.
|
||||
And I am on the "Course 1" "reset" page logged in as admin
|
||||
And I press "Reset"
|
||||
And I press "Continue"
|
||||
# Confirm that forum discussion tags are not deleted.
|
||||
When I am on the "Test Forum" "forum activity" page
|
||||
And I follow "Discussion 1"
|
||||
Then I should see "SampleTag"
|
||||
And I should see "DiscussionTag"
|
||||
And I am on the "Course 1" "reset" page
|
||||
And I expand all fieldsets
|
||||
# Depending on <resetcheck> value, either delete all discussion posts or remove all forum discussion tags only.
|
||||
And I click on "<resetcheck>" "checkbox"
|
||||
# Confirm `Remove all forum tags` is disabled when `Delete all posts` on previous step is checked.
|
||||
And the "Remove all forum tags" "checkbox" should be <canbechecked>
|
||||
And I press "Reset"
|
||||
And I should see "<resetmessage>" in the "Forums" "table_row"
|
||||
And I press "Continue"
|
||||
And I am on the "Test Forum" "forum activity" page
|
||||
# Confirm discussion is deleted when `Delete all posts` was checked.
|
||||
And I <forumview> see "There are no discussion topics yet in this forum"
|
||||
# Confirm all discussion tags are deleted.
|
||||
And I should not see "SampleTag"
|
||||
And I should not see "DiscussionTag"
|
||||
|
||||
Examples:
|
||||
| resetcheck | resetmessage | canbechecked | forumview |
|
||||
| Delete all posts | Delete all posts | disabled | should |
|
||||
| Remove all forum tags | Forum tags have been deleted | enabled | should not |
|
||||
|
||||
@javascript
|
||||
Scenario Outline: Delete glossary entry tags using course reuse
|
||||
Given the following "mod_glossary > entries" exist:
|
||||
| glossary | concept | definition | user | tags |
|
||||
| Test Glossary | Aubergine | Also eggpgplant | admin | SampleTag, GlossaryTag |
|
||||
# Perform course reset without checking anything.
|
||||
And I am on the "Course 1" "reset" page logged in as admin
|
||||
And I press "Reset"
|
||||
And I press "Continue"
|
||||
# Confirm that glossary entry tags are not deleted.
|
||||
When I am on the "Test Glossary" "glossary activity" page
|
||||
Then I should see "SampleTag"
|
||||
And I should see "GlossaryTag"
|
||||
And I am on the "Course 1" "reset" page
|
||||
And I expand all fieldsets
|
||||
# Depending on <resetcheck> value, either delete all glossary entries or remove all glossary entry tags only.
|
||||
And I click on "<resetcheck>" "checkbox"
|
||||
# Confirm `Remove all forum tags` is disabled when `Delete entries from all glossaries` on previous step is checked.
|
||||
And the "Remove all glossary tags" "checkbox" should be <canbechecked>
|
||||
And I press "Reset"
|
||||
And I should see "<resetmessage>" in the "Glossaries" "table_row"
|
||||
And I press "Continue"
|
||||
And I am on the "Test Glossary" "glossary activity" page
|
||||
# Confirm glossary entries are deleted when `Delete entries from all glossaries` is checked.
|
||||
And I <glossaryview> see "No entries found in this section"
|
||||
# Confirm that glossary entry tags are deleted.
|
||||
And I should not see "SampleTag"
|
||||
And I should not see "GlossaryTag"
|
||||
|
||||
Examples:
|
||||
| resetcheck | resetmessage | canbechecked | glossaryview |
|
||||
| Delete entries from all glossaries | Delete entries from all glossaries | disabled | should |
|
||||
| Remove all glossary tags | Glossary tags have been deleted | enabled | should not |
|
||||
@@ -33,11 +33,6 @@ Feature: Course activity controls works as expected
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I click on <targetpage> "link" in the "region-main" "region"
|
||||
And I add the "Recent activity" block
|
||||
And I open the action menu in "Recent activity" "block"
|
||||
And I click on "Delete Recent activity block" "link"
|
||||
And I click on "Delete" "button" in the "Delete block?" "dialogue"
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I open "Test forum name 1" actions menu
|
||||
And I click on "Edit settings" "link" in the "Test forum name 1" activity
|
||||
@@ -100,10 +95,6 @@ Feature: Course activity controls works as expected
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I click on <targetpage> "link" in the "region-main" "region"
|
||||
And I add the "Recent activity" block
|
||||
And I open the action menu in "Recent activity" "block"
|
||||
And I click on "Delete Recent activity block" "link"
|
||||
And I press "Yes"
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I click on "Edit settings" "link" in the "Test forum name 1" activity
|
||||
And I should see "Updating Forum"
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
@core @core_course
|
||||
Feature: Students can view their grades and activity reports
|
||||
In order for students to view their grades and activity reports
|
||||
As a teacher
|
||||
I should be able to change the report display settings
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
|
||||
Scenario Outline: Grade reports can be displayed or hidden to students
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | showgrades |
|
||||
| Course 1 | C1 | <gradevisibility> |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
When I am on the "student1" "user > profile" page logged in as student1
|
||||
And I click on "Course 1" "link"
|
||||
Then I <gradelinkvisibility> see "Grades overview"
|
||||
|
||||
Examples:
|
||||
| gradevisibility | gradelinkvisibility |
|
||||
| 1 | should |
|
||||
| 0 | should not |
|
||||
|
||||
Scenario Outline: Activity reports can be displayed or hidden to students
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | showreports |
|
||||
| Course 1 | C1 | <reportvisibility> |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
When I am on the "student1" "user > profile" page logged in as student1
|
||||
And I click on "Course 1" "link"
|
||||
Then I <reportlinkvisibility> see "Today's logs"
|
||||
And I <reportlinkvisibility> see "All logs"
|
||||
And I <reportlinkvisibility> see "Outline report"
|
||||
And I <reportlinkvisibility> see "Complete report"
|
||||
|
||||
Examples:
|
||||
| reportvisibility | reportlinkvisibility |
|
||||
| 1 | should |
|
||||
| 0 | should not |
|
||||
@@ -37,8 +37,7 @@ require_once($CFG->dirroot . '/webservice/tests/helpers.php');
|
||||
* @copyright 2012 Jerome Mouneyrac
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class externallib_test extends externallib_advanced_testcase {
|
||||
//core_course_externallib_testcase
|
||||
final class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
/**
|
||||
* Tests set up
|
||||
@@ -598,7 +597,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function course_empty_field_provider(): array {
|
||||
public static function course_empty_field_provider(): array {
|
||||
return [
|
||||
[[
|
||||
'fullname' => '',
|
||||
@@ -3092,7 +3091,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
/**
|
||||
* Test cases for the get_enrolled_courses_by_timeline_classification test.
|
||||
*/
|
||||
public function get_get_enrolled_courses_by_timeline_classification_test_cases():array {
|
||||
public static function get_get_enrolled_courses_by_timeline_classification_test_cases(): array {
|
||||
$now = time();
|
||||
$day = 86400;
|
||||
|
||||
@@ -3349,16 +3348,6 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()',
|
||||
],
|
||||
'all limit and offset with wrong sort direction' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => "ul.timeaccess abcdasc",
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid sort direction in $sort parameter in enrol_get_my_courses()',
|
||||
],
|
||||
'all limit and offset with wrong sort direction' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
@@ -3379,16 +3368,6 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()',
|
||||
],
|
||||
'all limit and offset with wrong field name' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => "ul.foobar",
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()',
|
||||
],
|
||||
'all limit and offset with wrong field separator' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
|
||||
@@ -21,12 +21,9 @@ Feature: Default value for the textarea custom field can contain images
|
||||
And the following "custom field categories" exist:
|
||||
| name | component | area | itemid |
|
||||
| Category for test | core_course | course | 0 |
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| private_files | System | 1 | my-index | side-post |
|
||||
And the following "user private files" exist:
|
||||
| user | filepath | filename |
|
||||
| admin | lib/tests/fixtures/gd-logo.png | gd-logo.png |
|
||||
| user | filepath |
|
||||
| admin | lib/tests/fixtures/gd-logo.png |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Courses > Course custom fields" in site administration
|
||||
And I click on "Add a new custom field" "link"
|
||||
|
||||
@@ -25,12 +25,9 @@ Feature: Teachers can edit course custom fields
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| private_files | System | 1 | my-index | side-post |
|
||||
And the following "user private files" exist:
|
||||
| user | filepath | filename |
|
||||
| admin | lib/tests/fixtures/gd-logo.png | gd-logo.png |
|
||||
| user | filepath |
|
||||
| admin | lib/tests/fixtures/gd-logo.png |
|
||||
|
||||
Scenario: Display custom fields on course edit form
|
||||
When I log in as "teacher1"
|
||||
|
||||
@@ -83,11 +83,11 @@ Feature: Cohort enrolment management
|
||||
And I navigate to course participants
|
||||
# Verifies students 1 and 4 are in the cohort and student 2 is not any more.
|
||||
And the following should exist in the "participants" table:
|
||||
| First name / Last name | Email address | Roles | Groups |
|
||||
| First name | Email address | Roles | Groups |
|
||||
| Sandra Cole | s1@example.com | Student | Alpha1 cohort |
|
||||
| Jane Doe | s4@example.com | Student | Alpha1 cohort |
|
||||
And the following should not exist in the "participants" table:
|
||||
| First name / Last name | Email address | Roles | Groups |
|
||||
| First name | Email address | Roles | Groups |
|
||||
| John Smith | s2@example.com | Student | Alpha1 cohort |
|
||||
|
||||
@javascript
|
||||
|
||||
@@ -39,8 +39,7 @@ require_once(__DIR__.'/lib.php');
|
||||
global $CFG, $DB, $PAGE, $USER;
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
require_login(null, false);
|
||||
|
||||
confirm_sesskey();
|
||||
require_sesskey();
|
||||
$launchid = required_param('launchid', PARAM_TEXT);
|
||||
$modules = optional_param_array('modules', [], PARAM_INT);
|
||||
$grades = optional_param_array('grades', [], PARAM_INT);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace enrol_lti\local\ltiadvantage\entity;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \enrol_lti\local\ltiadvantage\entity\user
|
||||
*/
|
||||
class user_test extends \advanced_testcase {
|
||||
final class user_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test creation of a user instance using the factory method.
|
||||
@@ -64,7 +64,7 @@ class user_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array the data for testing.
|
||||
*/
|
||||
public function create_data_provider(): array {
|
||||
public static function create_data_provider(): array {
|
||||
global $CFG;
|
||||
return [
|
||||
'Valid create, only required args provided' => [
|
||||
@@ -272,7 +272,7 @@ class user_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array the data for testing.
|
||||
*/
|
||||
public function create_from_resource_link_data_provider(): array {
|
||||
public static function create_from_resource_link_data_provider(): array {
|
||||
global $CFG;
|
||||
return [
|
||||
'Valid creation, all args provided explicitly' => [
|
||||
@@ -511,7 +511,7 @@ class user_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array the array of test data.
|
||||
*/
|
||||
public function setters_getters_data_provider(): array {
|
||||
public static function setters_getters_data_provider(): array {
|
||||
global $CFG;
|
||||
return [
|
||||
'Testing set_resourcelinkid with valid id' => [
|
||||
@@ -620,12 +620,12 @@ class user_test extends \advanced_testcase {
|
||||
],
|
||||
'Testing set_maildisplay with a valid int: 2' => [
|
||||
'methodname' => 'maildisplay',
|
||||
'arg' => '1',
|
||||
'arg' => '2',
|
||||
'expectations' => [
|
||||
'valid' => true,
|
||||
]
|
||||
],
|
||||
'Testing set_maildisplay with invalid int' => [
|
||||
'Testing set_maildisplay with invalid int: -1' => [
|
||||
'methodname' => 'maildisplay',
|
||||
'arg' => '-1',
|
||||
'expectations' => [
|
||||
@@ -634,7 +634,7 @@ class user_test extends \advanced_testcase {
|
||||
'exceptionmessage' => "Invalid maildisplay value '-1'. Must be in the range {0..2}."
|
||||
]
|
||||
],
|
||||
'Testing set_maildisplay with invalid int' => [
|
||||
'Testing set_maildisplay with invalid int: 3' => [
|
||||
'methodname' => 'maildisplay',
|
||||
'arg' => '3',
|
||||
'expectations' => [
|
||||
@@ -659,7 +659,7 @@ class user_test extends \advanced_testcase {
|
||||
'exceptionmessage' => 'Invalid lang value. Cannot be an empty string.'
|
||||
]
|
||||
],
|
||||
'Testing set_lang with an empty string' => [
|
||||
'Testing set_lang with invalid lang code' => [
|
||||
'methodname' => 'lang',
|
||||
'arg' => 'ff',
|
||||
'expectations' => [
|
||||
|
||||
@@ -9,6 +9,7 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
@@ -64,13 +65,13 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
|
||||
Scenario: Self-enrolment enabled requiring a group enrolment key
|
||||
Given I log in as "teacher1"
|
||||
When I add "Self enrolment" enrolment method in "Course 1" with:
|
||||
| Custom instance name | Test student enrolment |
|
||||
| Enrolment key | moodle_rules |
|
||||
| Use group enrolment keys | Yes |
|
||||
| Custom instance name | Test student enrolment |
|
||||
| Enrolment key | moodle_rules |
|
||||
| Use group enrolment keys | Yes |
|
||||
And I am on the "Course 1" "groups" page
|
||||
And I press "Create group"
|
||||
And I set the following fields to these values:
|
||||
| Group name | Group 1 |
|
||||
| Group name | Group 1 |
|
||||
| Enrolment key | Test-groupenrolkey1 |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
@@ -82,6 +83,16 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
|
||||
Then I should see "Topic 1"
|
||||
And I should not see "Enrolment options"
|
||||
And I should not see "Enrol me in this course"
|
||||
And I am on the "Course 1" course page logged in as student2
|
||||
And I set the following fields to these values:
|
||||
| Enrolment key | moodle_rules |
|
||||
And I press "Enrol me"
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to course participants
|
||||
And the following should exist in the "participants" table:
|
||||
| First name | Email address | Roles | Groups |
|
||||
| Student 1 | student1@example.com | Student | Group 1 |
|
||||
| Student 2 | student2@example.com | Student | No groups |
|
||||
|
||||
@javascript
|
||||
Scenario: Edit a self-enrolled user's enrolment from the course participants page
|
||||
|
||||
@@ -37,12 +37,12 @@ require_once($CFG->dirroot . '/enrol/externallib.php');
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 2.4
|
||||
*/
|
||||
class externallib_test extends externallib_advanced_testcase {
|
||||
final class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
/**
|
||||
* dataProvider for test_get_enrolled_users_visibility().
|
||||
*/
|
||||
public function get_enrolled_users_visibility_provider() {
|
||||
public static function get_enrolled_users_visibility_provider(): array {
|
||||
return array(
|
||||
'Course without groups, default behavior (not filtering by cap, group, active)' =>
|
||||
array(
|
||||
@@ -231,7 +231,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
),
|
||||
),
|
||||
|
||||
'Course with separate groups, filtering by withcapability (having moodle/role:review)' =>
|
||||
'Course with separate groups, filtering by withcapability (having moodle/role:review & moodle/course:bulkmessaging)' =>
|
||||
array(
|
||||
'settings' => array(
|
||||
'coursegroupmode' => SEPARATEGROUPS,
|
||||
@@ -327,8 +327,9 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$this->expectExceptionMessage($exception['message']);
|
||||
} else {
|
||||
// Failed, only canview and exception are supported.
|
||||
$this->markTestIncomplete('Incomplete, only canview and exception are supported');
|
||||
throw new \coding_exception('Incomplete, only canview and exception are supported');
|
||||
}
|
||||
|
||||
// Switch to the user and assign the role.
|
||||
$this->setUser(${$user});
|
||||
role_assign($roleid, $USER->id, $coursecontext);
|
||||
@@ -1105,7 +1106,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
/**
|
||||
* dataProvider for test_submit_user_enrolment_form().
|
||||
*/
|
||||
public function submit_user_enrolment_form_provider() {
|
||||
public static function submit_user_enrolment_form_provider(): array {
|
||||
$now = new \DateTime();
|
||||
|
||||
$nextmonth = clone($now);
|
||||
|
||||
@@ -14,9 +14,6 @@ Feature: Render H5P content using filters
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| private_files | System | 1 | my-index | side-post |
|
||||
And the "displayh5p" filter is "on"
|
||||
And the following config values are set as admin:
|
||||
| allowedsources | https://moodle.h5p.com/content/[id]/embed | filter_displayh5p |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@editor @editor_atto @atto @atto_h5p @filter @filter_displayh5p @core_h5p @_file_upload @_switch_iframe
|
||||
@editor @editor_atto @atto @atto_h5p @filter @filter_displayh5p @core_h5p @_switch_iframe
|
||||
Feature: Inline editing H5P content anywhere
|
||||
In order to edit an existing H5P content
|
||||
As a user
|
||||
@@ -30,23 +30,17 @@ Feature: Inline editing H5P content anywhere
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| moodle/course:update | Allow | teacher | System | |
|
||||
| moodle/course:update | Allow | student | System | |
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| private_files | System | 1 | my-index | side-post |
|
||||
|
||||
@javascript @mod @mod_page
|
||||
Scenario: Edit H5P content from a page using link to private file
|
||||
Given the following "permission overrides" exist:
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| moodle/h5p:updatelibraries | Allow | editingteacher | System | |
|
||||
And I log in as "teacher1"
|
||||
# Upload the H5P to private user files.
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/greeting-card.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
And the following "user private file" exists:
|
||||
| user | teacher1 |
|
||||
| filepath | h5p/tests/fixtures/greeting-card.h5p |
|
||||
# Add H5P content to the page.
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "PageName1" "page activity" page
|
||||
And I am on the "PageName1" "page activity" page logged in as "teacher1"
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
|
||||
|
||||
@@ -14,26 +14,17 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace filter_multilang;
|
||||
|
||||
/**
|
||||
* Unit tests.
|
||||
* Tests for filter_multilang.
|
||||
*
|
||||
* @package filter_multilang
|
||||
* @category test
|
||||
* @copyright 2019 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace filter_multilang;
|
||||
|
||||
use filter_multilang;
|
||||
|
||||
/**
|
||||
* Tests for filter_multilang.
|
||||
*
|
||||
* @copyright 2019 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class filter_test extends \advanced_testcase {
|
||||
final class filter_test extends \advanced_testcase {
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
@@ -62,7 +53,7 @@ class filter_test extends \advanced_testcase {
|
||||
/**
|
||||
* Data provider for multi-language filtering tests.
|
||||
*/
|
||||
public function multilang_testcases() {
|
||||
public static function multilang_testcases(): array {
|
||||
return [
|
||||
'Basic case EN' => [
|
||||
'English',
|
||||
@@ -79,7 +70,7 @@ class filter_test extends \advanced_testcase {
|
||||
'<span lang="fr" class="multilang">Français</span><span class="multilang" lang="en">English</span>',
|
||||
'en',
|
||||
],
|
||||
'Reversed input order EN' => [
|
||||
'Reversed input order FR' => [
|
||||
'Français',
|
||||
'<span lang="fr" class="multilang">Français</span><span class="multilang" lang="en">English</span>',
|
||||
'fr',
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ function filter_tex_sanitize_formula(string $texexp): string {
|
||||
'\afterassignment', '\expandafter', '\noexpand', '\special',
|
||||
'\let', '\futurelet', '\else', '\fi', '\chardef', '\makeatletter', '\afterground',
|
||||
'\noexpand', '\line', '\mathcode', '\item', '\section', '\mbox', '\declarerobustcommand',
|
||||
'\ExplSyntaxOn',
|
||||
'\ExplSyntaxOn', '\pdffiledump',
|
||||
];
|
||||
|
||||
$allowlist = ['inputenc'];
|
||||
|
||||
@@ -49,6 +49,7 @@ class lib_test extends advanced_testcase {
|
||||
['x\ =\ \frac{\sqrt{144}}{2}\ \times\ (y\ +\ 12)', 'x\ =\ \frac{\sqrt{144}}{2}\ \times\ (y\ +\ 12)'],
|
||||
['\usepackage[latin1]{inputenc}', '\usepackage[latin1]{inputenc}'],
|
||||
['\newcommand{\A}{\verbatiminput}', '\newforbiddenkeyword_command{\A}{\verbatimforbiddenkeyword_input}'],
|
||||
['\pdffiledump offset 0 length', 'forbiddenkeyword_\pdffiledump offset 0 length'],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -14,14 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit test for the filter_urltolink
|
||||
*
|
||||
* @package filter_urltolink
|
||||
* @category phpunit
|
||||
* @copyright 2010 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace filter_urltolink;
|
||||
|
||||
@@ -32,10 +24,22 @@ defined('MOODLE_INTERNAL') || die();
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/filter/urltolink/filter.php'); // Include the code to test
|
||||
|
||||
/**
|
||||
* Unit test for the filter_urltolink
|
||||
*
|
||||
* @package filter_urltolink
|
||||
* @category test
|
||||
* @copyright 2010 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
final class filter_test extends \basic_testcase {
|
||||
|
||||
class filter_test extends \basic_testcase {
|
||||
|
||||
function get_convert_urls_into_links_test_cases() {
|
||||
/**
|
||||
* Data provider for {@see test_convert_urls_into_links}
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_convert_urls_into_links_test_cases(): array {
|
||||
// Create a 4095 and 4096 long URLs.
|
||||
$superlong4095 = str_pad('http://www.superlong4095.com?this=something', 4095, 'a');
|
||||
$superlong4096 = str_pad('http://www.superlong4096.com?this=something', 4096, 'a');
|
||||
@@ -165,7 +169,6 @@ class filter_test extends \basic_testcase {
|
||||
'URL: <span style="kasd"> my link to http://google.com </span>' => 'URL: <span style="kasd"> my link to <a href="http://google.com" class="_blanktarget">http://google.com</a> </span>',
|
||||
// Nested tags test.
|
||||
'<b><i>www.google.com</i></b>' => '<b><i><a href="http://www.google.com" class="_blanktarget">www.google.com</a></i></b>',
|
||||
'<input type="submit" value="Go to http://moodle.org">' => '<input type="submit" value="Go to http://moodle.org">',
|
||||
// Test realistic content.
|
||||
'<p><span style="color: rgb(37, 37, 37); font-family: sans-serif; line-height: 22.3999996185303px;">Lorem ipsum amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut http://google.com aliquip ex ea <a href="http://google.com">commodo consequat</a>. Duis aute irure in reprehenderit in excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia https://docs.google.com/document/d/BrokenLinkPleaseAyacDHc_Ov8aoskoSVQsfmLHP_jYAkRMk/edit?usp=sharing https://docs.google.com/document/d/BrokenLinkPleaseAyacDHc_Ov8aoskoSVQsfmLHP_jYAkRMk/edit?usp=sharing mollit anim id est laborum.</span><br></p>'
|
||||
=>
|
||||
|
||||
@@ -95,16 +95,24 @@ class get_enrolled_users_for_search_widget extends external_api {
|
||||
|
||||
$users = [];
|
||||
|
||||
$userfieldsapi = \core_user\fields::for_identity($coursecontext, false)->with_userpic();
|
||||
$extrauserfields = $userfieldsapi->get_required_fields([\core_user\fields::PURPOSE_IDENTITY]);
|
||||
|
||||
while ($userdata = $gui->next_user()) {
|
||||
$guiuser = $userdata->user;
|
||||
$user = new \stdClass();
|
||||
$user->fullname = fullname($guiuser);
|
||||
foreach (\core_user\fields::get_name_fields() as $field) {
|
||||
$user->$field = $guiuser->$field ?? null;
|
||||
}
|
||||
$user->id = $guiuser->id;
|
||||
$user->url = (new moodle_url($actionbaseurl, ['id' => $courseid, 'userid' => $guiuser->id]))->out(false);
|
||||
$userpicture = new \user_picture($guiuser);
|
||||
$userpicture->size = 1;
|
||||
$user->profileimage = $userpicture->get_url($PAGE)->out(false);
|
||||
$user->email = $guiuser->email;
|
||||
foreach ($extrauserfields as $field) {
|
||||
$user->$field = $userdata->user->$field ?? null;
|
||||
}
|
||||
$user->active = false; // @TODO MDL-76246
|
||||
|
||||
$users[] = $user;
|
||||
|
||||
@@ -70,3 +70,31 @@ Feature: Display marking guide information to students
|
||||
| criteria | description | remark | maxscore | criteriascore |
|
||||
| Grade Criteria 1 | Grade 1 description for students | Excellent work! | 70 | 50 / 70 |
|
||||
| Grade Criteria 2 | Grade 2 description for students | Try harder | 30 | 20 / 30 |
|
||||
|
||||
Scenario: Confirm that marking guide definition is retained when grading method is changed
|
||||
Given I am on the "Assign 1" "assign activity" page
|
||||
And I go to "Student 1" "Assign 1" activity advanced grading page
|
||||
And I grade by filling the marking guide with:
|
||||
| Grade Criteria 1 | 70 | Well done! |
|
||||
| Grade Criteria 2 | 20 | Great work |
|
||||
And I press "Save changes"
|
||||
And I am on the "Assign 1" "assign activity editing" page
|
||||
And I set the following fields to these values:
|
||||
| Grading method | Simple direct grading |
|
||||
And I press "Save and return to course"
|
||||
When I go to "Assign 1" advanced grading page
|
||||
Then I should not see "Assign 1 marking guide Ready for use"
|
||||
And I should not see "Grade Critera 1"
|
||||
And I should not see "Grade Critera 2"
|
||||
And I am on the "Course 1" "grades > Grader report > View" page
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -3- | -4- |
|
||||
| Student 1 | student1@example.com | 90 |
|
||||
And I am on the "Assign 1" "assign activity editing" page
|
||||
And I set the following fields to these values:
|
||||
| Grading method | Marking guide |
|
||||
And I press "Save and return to course"
|
||||
And I go to "Assign 1" advanced grading page
|
||||
And I should see "Assign 1 marking guide Ready for use"
|
||||
And I should see "Grade Criteria 1"
|
||||
And I should see "Grade Criteria 2"
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
@gradingform @gradingform_guide
|
||||
Feature: Teacher can define a marking guide
|
||||
As a teacher,
|
||||
I should be able to define a marking guide
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firtname | lastname | email |
|
||||
| teacher1 | Teacher | One | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | course | name | advancedgradingmethod_submissions |
|
||||
| assign | C1 | Assign 1 | guide |
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I go to "Assign 1" advanced grading definition page
|
||||
And I set the following fields to these values:
|
||||
| Name | Marking guide 1 |
|
||||
|
||||
Scenario: No criterion added to marking guide
|
||||
When I press "Save as draft"
|
||||
# Confirm that criterion parameters are required
|
||||
Then I should see "Criterion name can not be empty"
|
||||
And I should see "Criterion max score can not be empty"
|
||||
# Confirm that marking guide is not saved due to the missing criterion
|
||||
And I should not see "Marking guide 1 Draft"
|
||||
And I should not see "Please note: the advanced grading form is not ready at the moment. Simple grading method will be used until the form has a valid status."
|
||||
|
||||
@javascript
|
||||
Scenario: Marking guide criterion is added to marking guide
|
||||
Given I define the following marking guide:
|
||||
| Criterion name | Description for students | Description for markers | Maximum score |
|
||||
| Criteria 1 | Criteria 1 description for student | Criteria 1 description for marker | 70 |
|
||||
| Criteria 2 | Criteria 2 description for student | Criteria 2 description for marker | 30 |
|
||||
# Move Criteria 1 below Criteria 2
|
||||
And I click on "Move down" "button" in the "Criteria 1" "table_row"
|
||||
When I press "Save as draft"
|
||||
And I go to "Assign 1" advanced grading definition page
|
||||
# Confirm that the order of criterion shown matches input -- Criteria 2 is listed before Criteria 1
|
||||
Then "Move down" "button" in the "Criteria 2" "table_row" should be visible
|
||||
And "Move up" "button" in the "Criteria 2" "table_row" should not be visible
|
||||
And "Move up" "button" in the "Criteria 1" "table_row" should be visible
|
||||
And "Move down" "button" in the "Criteria 1" "table_row" should not be visible
|
||||
# Confirm the other information entered were saved
|
||||
And I should see "Criteria 2 description for student" in the "Criteria 2" "table_row"
|
||||
And I should see "Criteria 2 description for marker" in the "Criteria 2" "table_row"
|
||||
And I should see "30" in the "Criteria 2" "table_row"
|
||||
And I should see "Criteria 1 description for student" in the "Criteria 1" "table_row"
|
||||
And I should see "Criteria 1 description for marker" in the "Criteria 1" "table_row"
|
||||
And I should see "70" in the "Criteria 1" "table_row"
|
||||
|
||||
Scenario: Marking guide options and frequently used comment are added to marking guide
|
||||
Given I define the following marking guide:
|
||||
| Criterion name | Description for students | Description for markers | Maximum score |
|
||||
| Criteria 1 | Criteria 1 description for student | Criteria 1 description for marker | 50 |
|
||||
| Criteria 2 | Criteria 2 description for student | Criteria 2 description for marker | 50 |
|
||||
# Add frequently used comments and other marking guide options
|
||||
And I define the following frequently used comments:
|
||||
| Comment 1 |
|
||||
| Comment 2 |
|
||||
And I set the following fields to these values:
|
||||
| Show guide definition to students | 1 |
|
||||
| Show marks per criterion to students | 0 |
|
||||
When I press "Save as draft"
|
||||
And I go to "Assign 1" advanced grading definition page
|
||||
# Confirm that frequently used comments and marking guide options specified during registration are retained
|
||||
Then I should see "Comment 1"
|
||||
And I should see "Comment 2"
|
||||
And the field "Show guide definition to students" matches value "1"
|
||||
And the field "Show marks per criterion to students" matches value "0"
|
||||
@@ -7,12 +7,14 @@ Feature: Teacher can delete marking guide
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | One | teacher1@example.com |
|
||||
| student1 | Student | One | student1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "activities" exist:
|
||||
| activity | course | name | advancedgradingmethod_submissions |
|
||||
| assign | C1 | Assign 1 | guide |
|
||||
@@ -25,13 +27,19 @@ Feature: Teacher can delete marking guide
|
||||
| Criterion 1 | Criterion 1 description for student | Criterion 1 description for markers | 100 |
|
||||
And I press "Save marking guide and make it ready"
|
||||
|
||||
@javascript
|
||||
Scenario: Delete a marking guide
|
||||
Given I am on the "Course 1" course page
|
||||
Given I am on the "Assign 1" "assign activity" page
|
||||
And I go to "Student One" "Assign 1" activity advanced grading page
|
||||
And I grade by filling the marking guide with:
|
||||
| Criterion 1 | 70 | Well done! |
|
||||
And I press "Save changes"
|
||||
And I go to "Assign 1" advanced grading page
|
||||
When I click on "Delete the currently defined form" "link"
|
||||
Then I should see "You are going to delete the grading form 'Marking guide 1' and all the associated information from 'Assign 1 (Submissions)'"
|
||||
And I press "Cancel"
|
||||
# Confirm that marking guide was not deleted if Cancel is pressed
|
||||
Then I should see "Marking guide 1 Ready for use"
|
||||
And I should see "Marking guide 1 Ready for use"
|
||||
And I should see "Criterion 1"
|
||||
And I click on "Delete the currently defined form" "link"
|
||||
And I press "Continue"
|
||||
@@ -39,3 +47,7 @@ Feature: Teacher can delete marking guide
|
||||
And I should see "Please note: the advanced grading form is not ready at the moment. Simple grading method will be used until the form has a valid status."
|
||||
And I should not see "Marking guide 1 Ready for use"
|
||||
And I should not see "Criterion 1"
|
||||
And I am on the "Course 1" "grades > Grader report > View" page
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -3- | -4- |
|
||||
| Student One | student1@example.com | 70 |
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
@gradingform @gradingform_guide
|
||||
Feature: Teacher can edit a marking guide state
|
||||
In order to change marking guide back to draft
|
||||
As a teacher
|
||||
I need to be able to edit the marking guide status
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | course | name | advancedgradingmethod_submissions |
|
||||
| assign | C1 | Assign 1 | guide |
|
||||
|
||||
Scenario: Marking guide state can be changed to draft
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
And I go to "Assign 1" advanced grading definition page
|
||||
And I set the following fields to these values:
|
||||
| Name | Assign 1 marking guide |
|
||||
| Description | Marking guide description |
|
||||
And I define the following marking guide:
|
||||
| Criterion name | Description for students | Description for markers | Maximum score |
|
||||
| Grade Criteria 1 | Grade 1 description for students | Grade 1 description for markers | 70 |
|
||||
| Grade Criteria 2 | Grade 2 description for students | Grade 2 description for markers | 30 |
|
||||
And I press "Save marking guide and make it ready"
|
||||
And I should not see "Please note: the advanced grading form is not ready at the moment. Simple grading method will be used until the form has a valid status."
|
||||
And I should not see "Assign 1 marking guide Draft"
|
||||
And I should see "Assign 1 marking guide Ready for use"
|
||||
And I click on "Edit the current form definition" "link"
|
||||
When I press "Save as draft"
|
||||
Then I should see "Please note: the advanced grading form is not ready at the moment. Simple grading method will be used until the form has a valid status."
|
||||
And I should see "Assign 1 marking guide Draft"
|
||||
And I should not see "Assign 1 marking guide Ready for use"
|
||||
@@ -68,9 +68,9 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
|
||||
And I should not see a feedback field for "Student 2" and grade item "Item VU"
|
||||
And I click on student "Student 3" for grade item "Item SU"
|
||||
And I set the field "ajaxgrade" to "Very good"
|
||||
And I press the shift tab key
|
||||
And I press the tab key
|
||||
And I press the shift tab key
|
||||
# Workaround for the Firefox 130.0 issue with the enter key and the old ajax grader element.
|
||||
And I click on student "Student 3" for grade item "Item SU"
|
||||
And I press the enter key
|
||||
And I click on student "Student 3" for grade item "Item VU"
|
||||
And I set the field "ajaxgrade" to "50"
|
||||
And I press the enter key
|
||||
|
||||
@@ -51,7 +51,7 @@ Feature: A teacher checks the grade history report in a course
|
||||
And I navigate to "View > Grade history" in the course gradebook
|
||||
When I press "Submit"
|
||||
Then the following should exist in the "gradereport_history" table:
|
||||
| First name/Last name | Email address | Favourite food | Grade item | Original grade | Revised grade | Grader |
|
||||
| First name | Email address | Favourite food | Grade item | Original grade | Revised grade | Grader |
|
||||
| Student 1 | student1@example.com | apple | The greatest assignment ever | | 50.00 | Teacher 1 |
|
||||
| Student 1 | student1@example.com | apple | Rewarding assignment | | 60.00 | Teacher 1 |
|
||||
| Student 2 | student2@example.com | orange | The greatest assignment ever | | 50.00 | Teacher 1 |
|
||||
@@ -79,7 +79,7 @@ Feature: A teacher checks the grade history report in a course
|
||||
And I press "Finish selecting users"
|
||||
And I press "Submit"
|
||||
And the following should exist in the "gradereport_history" table:
|
||||
| First name/Last name | Grade item | Original grade | Revised grade | Grader |
|
||||
| First name | Grade item | Original grade | Revised grade | Grader |
|
||||
| Student 1 | The greatest assignment ever | | 50.00 | Teacher 1 |
|
||||
| Student 1 | Rewarding assignment | | 60.00 | Teacher 1 |
|
||||
| Student 1 | The greatest assignment ever | 50.00 | 70.00 | Teacher 2 |
|
||||
@@ -96,7 +96,7 @@ Feature: A teacher checks the grade history report in a course
|
||||
And I set the field "Grade item" to "The greatest assignment ever"
|
||||
And I press "Submit"
|
||||
And the following should exist in the "gradereport_history" table:
|
||||
| First name/Last name | Grade item | Original grade | Revised grade | Grader |
|
||||
| First name | Grade item | Original grade | Revised grade | Grader |
|
||||
| Student 1 | The greatest assignment ever | | 50.00 | Teacher 1 |
|
||||
| Student 1 | The greatest assignment ever | 50.00 | 70.00 | Teacher 2 |
|
||||
And the following should not exist in the "gradereport_history" table:
|
||||
@@ -106,7 +106,7 @@ Feature: A teacher checks the grade history report in a course
|
||||
And I set the field "Grader" to "Teacher 1"
|
||||
And I press "Submit"
|
||||
And the following should exist in the "gradereport_history" table:
|
||||
| First name/Last name | Email address | Favourite food | Grade item | Original grade | Revised grade | Grader |
|
||||
| First name | Email address | Favourite food | Grade item | Original grade | Revised grade | Grader |
|
||||
| Student 1 | student1@example.com | apple | The greatest assignment ever | | 50.00 | Teacher 1 |
|
||||
And the following should not exist in the "gradereport_history" table:
|
||||
| Student 1 | The greatest assignment ever | 50.00 | 70.00 | Teacher 2 |
|
||||
@@ -114,5 +114,5 @@ Feature: A teacher checks the grade history report in a course
|
||||
And I click on "id_revisedonly" "checkbox"
|
||||
And I press "Submit"
|
||||
And the following should exist in the "gradereport_history" table:
|
||||
| First name/Last name | Email address | Favourite food | Grade item | Original grade | Revised grade | Grader |
|
||||
| First name | Email address | Favourite food | Grade item | Original grade | Revised grade | Grader |
|
||||
| Student 1 | student1@example.com | apple | The greatest assignment ever | | 50.00 | Teacher 1 |
|
||||
|
||||
@@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2014 Frédéric Massart - FMCorz.net
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class report_test extends \advanced_testcase {
|
||||
final class report_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Create some grades.
|
||||
@@ -251,7 +251,7 @@ class report_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array List of data sets (test cases)
|
||||
*/
|
||||
public function get_users_with_profile_fields_provider(): array {
|
||||
public static function get_users_with_profile_fields_provider(): array {
|
||||
return [
|
||||
// User identity check boxes, 'email', 'profile_field_lang' and 'profile_field_height' are checked.
|
||||
'show email,lang and height;search for all users' =>
|
||||
@@ -264,24 +264,18 @@ class report_test extends \advanced_testcase {
|
||||
['email,profile_field_lang,profile_field_height', '.uk', ['u3']],
|
||||
'show email,lang and height,search for Spanish speakers' =>
|
||||
['email,profile_field_lang,profile_field_height', 'spanish', ['u1', 'u4']],
|
||||
'show email,lang and height,search for Spanish speakers' =>
|
||||
'show email,lang and height,search for Spanish speakers (using spa)' =>
|
||||
['email,profile_field_lang,profile_field_height', 'spa', ['u1', 'u4']],
|
||||
'show email,lang and height,search for German speakers' =>
|
||||
['email,profile_field_lang,profile_field_height', 'german', ['u2']],
|
||||
'show email,lang and height,search for German speakers' =>
|
||||
'show email,lang and height,search for German speakers (using ger)' =>
|
||||
['email,profile_field_lang,profile_field_height', 'ger', ['u2']],
|
||||
'show email,lang and height,search for English speakers' =>
|
||||
['email,profile_field_lang,profile_field_height', 'english', ['u3']],
|
||||
'show email,lang and height,search for English speakers' =>
|
||||
'show email,lang and height,search for English speakers (using eng)' =>
|
||||
['email,profile_field_lang,profile_field_height', 'eng', ['u3']],
|
||||
'show email,lang and height,search for English speakers' =>
|
||||
['email,profile_field_lang,profile_field_height', 'ish', ['u3']],
|
||||
'show email,lang and height,search for users with height 180cm' =>
|
||||
['email,profile_field_lang,profile_field_height', '180cm', ['u2', 'u3', 'u4']],
|
||||
'show email,lang and height,search for users with height 180cm' =>
|
||||
['email,profile_field_lang,profile_field_height', '180', ['u2', 'u3', 'u4']],
|
||||
'show email,lang and height,search for users with height 170cm' =>
|
||||
['email,profile_field_lang,profile_field_height', '170cm', ['u1']],
|
||||
'show email,lang and height,search for users with height 170cm' =>
|
||||
['email,profile_field_lang,profile_field_height', '170', ['u1']],
|
||||
|
||||
@@ -292,25 +286,15 @@ class report_test extends \advanced_testcase {
|
||||
['email,profile_field_height', '.com', []],
|
||||
'show email and height;search for users on .co' =>
|
||||
['email,profile_field_height', '.co', ['u3']],
|
||||
'show email and height,search for Spanish/German/English speakers' =>
|
||||
'show email and height,search for Spanish speakers' =>
|
||||
['email,profile_field_height', 'spanish', []],
|
||||
'show email and height,search for Spanish/German/English speakers' =>
|
||||
'show email and height,search for German speakers' =>
|
||||
['email,profile_field_height', 'german', []],
|
||||
'show email and height,search for Spanish/German/English speakers' =>
|
||||
['email,profile_field_height', 'english', []],
|
||||
'show email,lang and height,search for English speakers' =>
|
||||
['email,profile_field_height', 'english', []],
|
||||
'show email and height,search for English speakers' =>
|
||||
['email,profile_field_height', 'eng', []],
|
||||
'show email and height,search for English speakers' =>
|
||||
['email,profile_field_height', 'ish', []],
|
||||
['email,profile_field_height', 'english', []],
|
||||
'show email and height,search for users with height 180cm' =>
|
||||
['email,profile_field_height', '180cm', ['u2', 'u3', 'u4']],
|
||||
'show email,lang and height,search for users with height 180cm' =>
|
||||
['email,profile_field_height', '180', ['u2', 'u3', 'u4']],
|
||||
'show email,lang and height,search for users with height 170cm' =>
|
||||
['email,profile_field_height', '170cm', ['u1']],
|
||||
'show email,lang and height,search for users with height 170cm' =>
|
||||
'show email and height,search for users with height 170cm' =>
|
||||
['email,profile_field_height', '170', ['u1']],
|
||||
|
||||
// User identity check boxes, only 'email' is checked.
|
||||
@@ -322,9 +306,7 @@ class report_test extends \advanced_testcase {
|
||||
'show email only;search for Spanish speakers' => ['email', 'spanish', []],
|
||||
'show email only;search for German speakers' => ['email', 'german', []],
|
||||
'show email only;search for English speakers' => ['email', 'english', []],
|
||||
'show email only;search for users with height 180cm' => ['email', '180cm', []],
|
||||
'show email only;search for users with height 180cm' => ['email', '180', []],
|
||||
'show email only;search for users with height 170cm' => ['email', '170cm', []],
|
||||
'show email only;search for users with height 170cm' => ['email', '170', []],
|
||||
];
|
||||
}
|
||||
@@ -401,7 +383,7 @@ class report_test extends \advanced_testcase {
|
||||
/**
|
||||
* Data provider method for \gradereport_history_report_testcase::test_get_users_with_groups()
|
||||
*/
|
||||
public function get_users_provider() {
|
||||
public static function get_users_provider(): array {
|
||||
return [
|
||||
'Visible groups, non-editing teacher, not in any group' => [
|
||||
VISIBLEGROUPS, 'teacher', ['g1', 'g2'], ['s1', 's2', 's3', 's4', 's5']
|
||||
|
||||
@@ -187,14 +187,9 @@ class user extends tablelike implements selectable_items {
|
||||
$itemicon = html_writer::div($this->format_icon($item), 'mr-1');
|
||||
$itemtype = \html_writer::span($this->structure->get_element_type_string($gradetreeitem),
|
||||
'd-block text-uppercase small dimmed_text');
|
||||
// If a behat test site is running avoid outputting the information about the type of the grade item.
|
||||
// This additional information currently causes issues in behat particularly with the existing xpath used to
|
||||
// interact with table elements.
|
||||
if (!defined('BEHAT_SITE_RUNNING')) {
|
||||
$itemcontent = html_writer::div($itemtype . $itemname);
|
||||
} else {
|
||||
$itemcontent = html_writer::div($itemname);
|
||||
}
|
||||
|
||||
$itemtitle = html_writer::div($itemname, 'rowtitle');
|
||||
$itemcontent = html_writer::div($itemtype . $itemtitle);
|
||||
|
||||
$line = [
|
||||
html_writer::div($itemicon . $itemcontent . $lockicon, "{$type} d-flex align-items-center"),
|
||||
|
||||
@@ -53,11 +53,20 @@ class gradereport_singleview_renderer extends plugin_renderer_base {
|
||||
// If a particular user option is selected (not in zero state).
|
||||
if ($userid) { // A single user selected.
|
||||
$user = core_user::get_user($userid);
|
||||
|
||||
$context = context_course::instance($course->id);
|
||||
$hiddenuserfields = explode(',', get_config('core', 'hiddenuserfields'));
|
||||
|
||||
// Determine whether the user's email can be displayed.
|
||||
$isemailvisible = !in_array('email', $hiddenuserfields) ||
|
||||
has_capability('moodle/course:viewhiddenuserfields', $context);
|
||||
|
||||
$data['selectedoption'] = [
|
||||
'image' => $this->user_picture($user, ['size' => 40, 'link' => false]),
|
||||
'text' => fullname($user),
|
||||
'additionaltext' => $user->email,
|
||||
'additionaltext' => $isemailvisible ? $user->email : '',
|
||||
];
|
||||
$data['userid'] = $userid;
|
||||
}
|
||||
|
||||
$this->page->requires->js_call_amd('gradereport_singleview/user', 'init');
|
||||
|
||||
@@ -55,6 +55,7 @@ Feature: We can use Single view
|
||||
And the following config values are set as admin:
|
||||
| fullnamedisplay | firstnamephonetic,lastnamephonetic |
|
||||
| alternativefullnameformat | middlename, alternatename, firstname, lastname |
|
||||
And I change window size to "large"
|
||||
And I am on the "Course 1" "grades > Grader report > View" page logged in as "teacher1"
|
||||
|
||||
Scenario: I can update grades, add feedback and exclude grades.
|
||||
@@ -93,7 +94,7 @@ Feature: We can use Single view
|
||||
And I press "Save"
|
||||
Then I should see "Grades were set for 1 items"
|
||||
And the following should exist in the "generaltable" table:
|
||||
| First name (Alternate name) Last name | Grade |
|
||||
| User full name | Grade |
|
||||
| Ann, Jill, Grainne, Beauchamp | Very good |
|
||||
And I am on the "Course 1" "grades > Single view > View" page logged in as "teacher2"
|
||||
And I click on "Users" "link" in the ".page-toggler" "css_element"
|
||||
|
||||
@@ -556,14 +556,8 @@ class user extends grade_report {
|
||||
}
|
||||
|
||||
// Generate the content for a cell that represents a grade item.
|
||||
// If a behat test site is running avoid outputting the information about the type of the grade item.
|
||||
// This additional information causes issues in behat particularly with the existing xpath used to
|
||||
// interact with table elements.
|
||||
if (!defined('BEHAT_SITE_RUNNING')) {
|
||||
$content = \html_writer::div($itemtype . $fullname);
|
||||
} else {
|
||||
$content = \html_writer::div($fullname);
|
||||
}
|
||||
$itemtitle = \html_writer::div($fullname, 'rowtitle');
|
||||
$content = \html_writer::div($itemtype . $itemtitle);
|
||||
|
||||
// Name.
|
||||
$data['itemname']['content'] = \html_writer::div($itemicon . $content, "{$type} d-flex align-items-center");
|
||||
|
||||
@@ -100,11 +100,20 @@ class gradereport_user_renderer extends plugin_renderer_base {
|
||||
if (!is_null($userid)) {
|
||||
if ($userid) { // A single user selected.
|
||||
$user = core_user::get_user($userid);
|
||||
|
||||
$context = context_course::instance($course->id);
|
||||
$hiddenuserfields = explode(',', get_config('core', 'hiddenuserfields'));
|
||||
|
||||
// Determine whether the user's email can be displayed.
|
||||
$isemailvisible = !in_array('email', $hiddenuserfields) ||
|
||||
has_capability('moodle/course:viewhiddenuserfields', $context);
|
||||
|
||||
$data['selectedoption'] = [
|
||||
'image' => $this->user_picture($user, ['size' => 40, 'link' => false]),
|
||||
'text' => fullname($user),
|
||||
'additionaltext' => $user->email,
|
||||
'image' => $this->user_picture($user, ['size' => 40, 'link' => false]),
|
||||
'text' => fullname($user),
|
||||
'additionaltext' => $isemailvisible ? $user->email : '',
|
||||
];
|
||||
$data['userid'] = $userid;
|
||||
} else { // All users selected.
|
||||
// Get the total number of users.
|
||||
$defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
|
||||
|
||||
@@ -28,3 +28,22 @@ Feature: Within the User report, a teacher can search for users.
|
||||
And I confirm "Student 2" in "user" search within the gradebook widget exists
|
||||
And I confirm "Student 32" in "user" search within the gradebook widget exists
|
||||
And I confirm "Student 1" in "user" search within the gradebook widget does not exist
|
||||
|
||||
Scenario: A teacher can only search for fields that he allowed to see
|
||||
Given the following "permission overrides" exist:
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| moodle/course:viewhiddenuserfields | Prohibit | editingteacher | System | |
|
||||
And the following config values are set as admin:
|
||||
| hiddenuserfields | email |
|
||||
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
|
||||
When I click on ".search-widget[data-searchtype='user']" "css_element"
|
||||
And I set the field "Search users" to "Student"
|
||||
And I confirm "Student 1" in "user" search within the gradebook widget exists
|
||||
And I confirm "Student 2" in "user" search within the gradebook widget exists
|
||||
And I confirm "Student 32" in "user" search within the gradebook widget exists
|
||||
# Email is not shown in results.
|
||||
And I confirm "Student" in "user" search within the gradebook widget exists
|
||||
And I confirm "example.com" in "user" search within the gradebook widget does not exist
|
||||
# Email is not searchable.
|
||||
And I set the field "Search users" to "student5@example.com"
|
||||
And I confirm "0 results found" in "user" search within the gradebook widget exists
|
||||
|
||||
@@ -50,14 +50,14 @@ Feature: We can use calculated grade totals
|
||||
| Test assignment nine | student1 | 5.00 |
|
||||
And I am on the "Course 1" "grades > Grader report > View" page logged in as "teacher1"
|
||||
And I turn editing mode on
|
||||
And I change window size to "large"
|
||||
# Change window size to ultra-wide to avoid 'out-of-bounds' random failures.
|
||||
And I change window size to "5120x2160"
|
||||
And I set the following settings for grade item "Test assignment two":
|
||||
| Hidden | 1 |
|
||||
And I set the following settings for grade item "Test assignment five":
|
||||
| Hidden | 1 |
|
||||
And I set the following settings for grade item "Test assignment eight":
|
||||
| Hidden | 1 |
|
||||
And I change window size to "medium"
|
||||
And I navigate to "Setup > Course grade settings" in the course gradebook
|
||||
And I set the field "Grade display type" to "Real (percentage)"
|
||||
And I press "Save changes"
|
||||
@@ -421,8 +421,6 @@ Feature: We can use calculated grade totals
|
||||
| Rescale existing grades | No |
|
||||
| Maximum grade | 200 |
|
||||
| Extra credit | 0 |
|
||||
# Change window size to ultra-wide to avoid 'out-of-bounds' random failures.
|
||||
And I change window size to "5120x2160"
|
||||
And I give the grade "21.00" to the user "Student 1" for the grade item "Manual item 2"
|
||||
And I press "Save changes"
|
||||
And I give the grade "20.00" to the user "Student 1" for the grade item "Manual item 2"
|
||||
@@ -434,8 +432,6 @@ Feature: We can use calculated grade totals
|
||||
| Rescale existing grades | No |
|
||||
| Maximum grade | 100 |
|
||||
| Extra credit | 0 |
|
||||
# Change window size to ultra-wide to avoid 'out-of-bounds' random failures.
|
||||
And I change window size to "5120x2160"
|
||||
And I give the grade "21.00" to the user "Student 1" for the grade item "Manual item 2"
|
||||
And I press "Save changes"
|
||||
And I give the grade "20.00" to the user "Student 1" for the grade item "Manual item 2"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@core @core_grades @javascript
|
||||
@core @core_grades
|
||||
Feature: Changing the aggregation of an item affects its weight and extra credit definition
|
||||
In order to switch to another aggregation method
|
||||
As an teacher
|
||||
@@ -31,7 +31,8 @@ Feature: Changing the aggregation of an item affects its weight and extra credit
|
||||
| Item b3 | C1 | Cat natural & | 1 | 0.10 | 1 |
|
||||
| Item b4 | C1 | Cat natural & | 1 | 0 | 0 |
|
||||
And I log in as "admin"
|
||||
And I change window size to "large"
|
||||
# Change window size to ultra-wide to avoid 'out-of-bounds' random failures.
|
||||
And I change window size to "5120x2160"
|
||||
And I set the following administration settings values:
|
||||
| grade_aggregations_visible | Mean of grades,Weighted mean of grades,Simple weighted mean of grades,Mean of grades (with extra credits),Median of grades,Lowest grade,Highest grade,Mode of grades,Natural |
|
||||
And I am on the "Course 1" "grades > Grader report > View" page
|
||||
@@ -54,8 +55,12 @@ Feature: Changing the aggregation of an item affects its weight and extra credit
|
||||
| Weight | 0 |
|
||||
| Extra credit | 1 |
|
||||
And I press "Save changes"
|
||||
And I follow "Edit Item a1"
|
||||
And the field "Weight adjusted" matches value "0"
|
||||
|
||||
Scenario: Verify grade item values
|
||||
Given I am on the "Course 1" "grades > Grader report > View" page logged in as "admin"
|
||||
And I turn editing mode on
|
||||
When I follow "Edit Item a1"
|
||||
Then the field "Weight adjusted" matches value "0"
|
||||
And the field "Extra credit" matches value "0"
|
||||
And I press "Cancel"
|
||||
And I follow "Edit Item a2"
|
||||
@@ -331,6 +336,7 @@ Feature: Changing the aggregation of an item affects its weight and extra credit
|
||||
And the field "Extra credit" matches value "0"
|
||||
And I press "Cancel"
|
||||
|
||||
@javascript
|
||||
Scenario: Switching grade items between categories
|
||||
# Move to same aggregation (Natural).
|
||||
Given I navigate to "Setup > Gradebook setup" in the course gradebook
|
||||
|
||||
@@ -46,6 +46,7 @@ Feature: Student and teacher's view of aggregated grade items is consistent when
|
||||
And I give the grade "50.00" to the user "Student 1" for the grade item "Test assignment one"
|
||||
And I give the grade "50.00" to the user "Student 1" for the grade item "Test assignment three"
|
||||
And I press "Save changes"
|
||||
And I change window size to "large"
|
||||
And I set the following settings for grade item "Test assignment four":
|
||||
| Hidden | 1 |
|
||||
And I press "Save changes"
|
||||
|
||||
@@ -62,7 +62,7 @@ Feature: An admin can import grades into gradebook using a CSV file
|
||||
And I should see "Grade import success"
|
||||
And I click on "Continue" "button"
|
||||
Then the following should exist in the "user-grades" table:
|
||||
| -1- | -1- | -4- | -5- |
|
||||
| -1- | -3- | -4- | -5- |
|
||||
| Student 1 | student1@example.com | 400.00 | 400.00 |
|
||||
| Student 2 | student2@example.com | 50.00 | 50.00 |
|
||||
| Student 3 | student3@example.com | 50.00 | 50.00 |
|
||||
|
||||
@@ -32,8 +32,8 @@ Feature: Regrading grades does not unnecessarily mark some as overriden
|
||||
And I press "Save changes"
|
||||
And I am on the "Course 1" "grades > Grader report > View" page
|
||||
And the following should exist in the "gradereport-grader-table" table:
|
||||
| | | |
|
||||
| First name / Last name | Assignment 1 | Course total |
|
||||
| -1- | -4- | -5- |
|
||||
| First name | Assignment 1 | Course total |
|
||||
| Student 1 | 80.00 | 80.00 |
|
||||
| Student 2 | 60.00 | 60.00 |
|
||||
And I turn editing mode on
|
||||
@@ -65,7 +65,7 @@ Feature: Regrading grades does not unnecessarily mark some as overriden
|
||||
When I am on the "Course 1" "grades > Grader report > View" page
|
||||
And I turn editing mode off
|
||||
Then the following should exist in the "gradereport-grader-table" table:
|
||||
| | | |
|
||||
| First name / Last name | Assignment 1 | Course total |
|
||||
| -1- | -4- | -5- |
|
||||
| First name | Assignment 1 | Course total |
|
||||
| Student 1 | 90.00 | 180.00 |
|
||||
| Student 2 | 70.00 | 160.00 |
|
||||
|
||||
@@ -43,17 +43,17 @@
|
||||
<div class="container mt-5">
|
||||
{{#exception}}
|
||||
<div class="alert alert-block fade in alert-danger my-2" role="alert">
|
||||
{{{ exception }}}
|
||||
{{ . }}
|
||||
</div>
|
||||
{{/exception}}
|
||||
{{#info}}
|
||||
<div class="alert alert-block fade in alert-info my-2" role="alert">
|
||||
{{{ . }}}
|
||||
{{ . }}
|
||||
</div>
|
||||
{{/info}}
|
||||
{{#error}}
|
||||
<div class="alert alert-block fade in alert-warning my-2" role="alert">
|
||||
{{#code}}{{{code}}} : {{/code}}{{{ message }}}
|
||||
{{#code}} {{ . }} : {{/code}} {{ message }}
|
||||
</div>
|
||||
{{/error}}
|
||||
</div>
|
||||
|
||||
+1
-4
@@ -478,7 +478,7 @@ if ($config->stage == INSTALL_DATABASE) {
|
||||
if ($hint_database !== '') {
|
||||
echo '<div class="alert alert-danger">'.$hint_database.'</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
install_print_footer($config);
|
||||
die;
|
||||
}
|
||||
@@ -610,11 +610,8 @@ if ($config->stage == INSTALL_PATHS) {
|
||||
if ($hint_admindir !== '') {
|
||||
echo '<div class="alert alert-danger">'.$hint_admindir.'</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
install_print_footer($config);
|
||||
die;
|
||||
}
|
||||
|
||||
@@ -39,4 +39,7 @@ $string['cannotdownloadzipfile'] = 'Не може да се изтегли ZIP
|
||||
$string['cannotfindcomponent'] = 'Не можа да намери компонент';
|
||||
$string['cannotunzipfile'] = 'Файлът не може да се разархивира';
|
||||
$string['componentisuptodate'] = 'Компонентът е актуален';
|
||||
$string['remotedownloaderror'] = 'Изтеглянето на компонента към вашия сървър пропадна, проверете настройките на proxy, препоръчително е PHP разширението cURL.<br /><br />Вие трябва ръчно да изтеглите файла <a href="{$a->url}">{$a->url}</a>, да го копирате в директория {$a->dest} на вашия сървър и да го разархивирате там.';
|
||||
$string['remotedownloaderror'] = '<p>Изтеглянето на компонента към вашия сървър пропадна, проверете настройките на proxy; препоръчително е PHP разширението cURL.</p><p>Вие трябва ръчно да изтеглите файла <a href="{$a->url}">{$a->url}</a>, да го копирате в директория "{$a->dest}" на вашия сървър и да го разархивирате там.</p>';
|
||||
$string['wrongdestpath'] = 'Грешен път към целта';
|
||||
$string['wrongsourcebase'] = 'Грешен изходен адрес';
|
||||
$string['wrongzipfilename'] = 'Грешно име на ZIP файл-а';
|
||||
|
||||
@@ -31,4 +31,4 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'ca';
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Català per a Workplace';
|
||||
$string['thislanguage'] = 'Català';
|
||||
|
||||
@@ -30,4 +30,4 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'da';
|
||||
$string['thislanguage'] = 'Dansk til Workplace';
|
||||
$string['thislanguage'] = 'Dansk';
|
||||
|
||||
@@ -82,5 +82,5 @@ $string['welcomep30'] = 'Diese Version von <strong>{$a->installername}</strong>
|
||||
$string['welcomep40'] = 'Das Paket enthält: <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
|
||||
$string['welcomep50'] = 'Die Verwendung aller Anwendungen in diesem Paket unterliegt den jeweiligen Lizenzen. Das vollständige Paket <strong>{$a->installername}</strong> ist <a href="https://www.opensource.org/docs/definition_plain.html">Open Source</a> und wird unter mit der Lizenz <a href="https://www.gnu.org/copyleft/gpl.html">GPL</a> angeboten.';
|
||||
$string['welcomep60'] = 'Die folgenden Webseiten führen Sie in einfachen Schritten durch die Installation von <strong>Moodle</strong> auf Ihrem Computer. Sie können die vorgeschlagenen Einstellungen übernehmen oder an eigene Bedürfnisse anpassen.';
|
||||
$string['welcomep70'] = 'Klicken Sie auf die Taste \'Weiter\', um mit der Installation von Moodle fortzufahren.';
|
||||
$string['welcomep70'] = 'Klicken Sie auf die Taste \'Weiter\', um mit der Installation von <strong>Moodle</strong> fortzufahren.';
|
||||
$string['wwwroot'] = 'Webadresse';
|
||||
|
||||
@@ -46,5 +46,5 @@ $string['phpversionhelp'] = '<p>Moodle erwartet PHP mindestens in der Version 4.
|
||||
(Im Falle von 5.0.x könntest du auch zu einer Version 4.3.x/4.4.x downgraden)</p>';
|
||||
$string['welcomep20'] = 'Du hast das Paket <strong>{$a->packname} {$a->packversion}</strong> erfolgreich auf deinem Computer installiert.';
|
||||
$string['welcomep30'] = 'Diese Version von <strong>{$a->installername}</strong> enthält folgende Anwendungen, mit denen du <strong>Moodle</strong> ausführen kannst:';
|
||||
$string['welcomep60'] = 'Die folgenden Seiten führen dich in einfachen Schritten durch die Konfiguration und Installation von <strong>Moodle</strong> auf deinem Computer. Du kannst die vorgeschlagenen Einstellungen übernehmen oder an deine Bedürfnisse anpassen.';
|
||||
$string['welcomep70'] = 'Klicke auf den "Weiter"-Button, um mit dem Setup von <string>Moodle</string> fortzufahren.';
|
||||
$string['welcomep60'] = 'Die folgenden Webseiten führen dich in einfachen Schritten durch die Installation von <strong>Moodle</strong> auf deinem Computer. Du können die vorgeschlagenen Einstellungen übernehmen oder an eigene Bedürfnisse anpassen.';
|
||||
$string['welcomep70'] = 'Klicke auf die Taste "Weiter", um mit der Installation von <strong>Moodle</strong> fortzufahren.';
|
||||
|
||||
@@ -31,4 +31,4 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'de_du';
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Deutsch (kids)';
|
||||
$string['thislanguage'] = 'Deutsch';
|
||||
|
||||
@@ -30,4 +30,4 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'el';
|
||||
$string['thislanguage'] = 'Ελληνικά για παιδιά';
|
||||
$string['thislanguage'] = 'Ελληνικά';
|
||||
|
||||
@@ -31,4 +31,4 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'el';
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Ελληνικά για χώρους εργασίας';
|
||||
$string['thislanguage'] = 'Ελληνικά';
|
||||
|
||||
@@ -30,4 +30,4 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'en';
|
||||
$string['thislanguage'] = 'English (kids)';
|
||||
$string['thislanguage'] = 'English';
|
||||
|
||||
@@ -30,4 +30,4 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'en_us';
|
||||
$string['thislanguage'] = 'English for Workplace - United States';
|
||||
$string['thislanguage'] = 'English (United States)';
|
||||
|
||||
@@ -29,4 +29,4 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['thislanguage'] = 'English for Workplace';
|
||||
$string['thislanguage'] = 'English';
|
||||
|
||||
@@ -33,3 +33,4 @@ $string['language'] = 'Idioma';
|
||||
$string['moodlelogo'] = 'Logo de Moodle';
|
||||
$string['next'] = 'Siguiente';
|
||||
$string['previous'] = 'Previo';
|
||||
$string['reload'] = 'Recargar';
|
||||
|
||||
@@ -30,4 +30,4 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'es_mx';
|
||||
$string['thislanguage'] = 'Español - México para niños';
|
||||
$string['thislanguage'] = 'Español - México';
|
||||
|
||||
@@ -31,4 +31,4 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'es';
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Español para la Empresa';
|
||||
$string['thislanguage'] = 'Español';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user