Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b90b0e6a8a | |||
| 58a55fcd40 | |||
| c37dd0ecbd | |||
| 84462c3e71 | |||
| 129b2186ac | |||
| 7eb6482266 | |||
| 9e4c3f858f | |||
| a7bbba41bf | |||
| bfc911b928 | |||
| 9766906cc5 | |||
| 0864e3adb3 | |||
| 86de73cb14 | |||
| b3e6ce7cfe | |||
| 94836d56b6 | |||
| 3477b9c1c5 | |||
| 6ee405e107 | |||
| 869b26f3e3 | |||
| d1f085a771 | |||
| 22ac74f686 | |||
| 72a51148e9 | |||
| 7e6d3caab7 | |||
| 0b15830a44 | |||
| 6c34850db6 | |||
| ed81c8df64 | |||
| efa1cab75a | |||
| aa99d2ebac | |||
| 9c4d90cb52 | |||
| 6a15f3890e | |||
| 4a4bf70e8b | |||
| 3aba658a40 | |||
| ed154e71b0 | |||
| 06d46b875b | |||
| 478b7146e5 | |||
| 5febdbe6a2 | |||
| 09e068e8bb | |||
| d17d7263fd | |||
| 0afaaad6dd | |||
| 556cdde71a | |||
| f24eb73cc5 | |||
| 01576f2100 | |||
| f39e564141 | |||
| ef1ecd2ad3 |
+1
-1
@@ -142,7 +142,7 @@ module.exports = function(grunt) {
|
||||
const path = require('path');
|
||||
const tasks = {};
|
||||
const async = require('async');
|
||||
const DOMParser = require('xmldom').DOMParser;
|
||||
const DOMParser = require('@xmldom/xmldom').DOMParser;
|
||||
const xpath = require('xpath');
|
||||
const semver = require('semver');
|
||||
const watchman = require('fb-watchman');
|
||||
|
||||
@@ -4109,6 +4109,8 @@
|
||||
</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_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -144,9 +144,7 @@ Feature: Manage plan workflow
|
||||
| name | user | description | status | reviewer |
|
||||
| Test-Plan3 | user1 | Description of plan 3 for user 1 | active | manager1 |
|
||||
| Test-Plan4 | user1 | Description of plan 4 for user 1 | active | manager1 |
|
||||
And I log in as "manager1"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I follow "User 1"
|
||||
And I am on the "user1" "user > profile" page logged in as "manager1"
|
||||
And I follow "Learning plans"
|
||||
And I should see "List of learning plans"
|
||||
And I follow "Learning plans"
|
||||
@@ -163,9 +161,7 @@ Feature: Manage plan workflow
|
||||
| name | user | description | status | reviewer |
|
||||
| Test-Plan3 | user1 | Description of plan 3 for user 1 | active | manager1 |
|
||||
| Test-Plan4 | user1 | Description of plan 4 for user 1 | active | manager1 |
|
||||
And I log in as "manager1"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I follow "User 1"
|
||||
And I am on the "user1" "user > profile" page logged in as "manager1"
|
||||
And I follow "Learning plans"
|
||||
And I should see "List of learning plans"
|
||||
And I follow "Learning plans"
|
||||
@@ -185,9 +181,7 @@ Feature: Manage plan workflow
|
||||
| name | user | description | status | reviewer |
|
||||
| Test-Plan3 | user1 | Description of plan 3 for user 1 | complete | manager1 |
|
||||
| Test-Plan4 | user1 | Description of plan 4 for user 1 | complete | manager1 |
|
||||
And I log in as "manager1"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I follow "User 1"
|
||||
And I am on the "user1" "user > profile" page logged in as "manager1"
|
||||
And I follow "Learning plans"
|
||||
And I should see "List of learning plans"
|
||||
And I follow "Learning plans"
|
||||
|
||||
@@ -241,9 +241,7 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
|
||||
And I set the field "I agree to the This site policy" to "1"
|
||||
And I press "Next"
|
||||
And I log out
|
||||
And I log in as "admin"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I follow "Manager"
|
||||
And I am on the "manager" "user > profile" page logged in as "admin"
|
||||
And I follow "Log in as"
|
||||
And I press "Continue"
|
||||
And I navigate to "Users > Privacy and policies > Manage policies" in site administration
|
||||
|
||||
@@ -562,9 +562,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| user1 | User | 1 | user1@example.com |
|
||||
When I log in as "admin"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I follow "User 1"
|
||||
When I am on the "user1" "user > profile" page logged in as "admin"
|
||||
And I follow "Log in as"
|
||||
Then I should see "You are logged in as User 1"
|
||||
And I press "Continue"
|
||||
@@ -603,8 +601,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I set the field "I agree to the This site policy" to "1"
|
||||
And I set the field "I agree to the This privacy policy" to "1"
|
||||
And I press "Next"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I follow "User 1"
|
||||
And I am on the "user1" "user > profile" page
|
||||
And I follow "Log in as"
|
||||
Then I should see "You are logged in as User 1"
|
||||
And I press "Continue"
|
||||
|
||||
@@ -146,6 +146,7 @@ Feature: My overview block pagination
|
||||
| student1 | C12 | student |
|
||||
| student1 | C13 | student |
|
||||
When I log in as "student1"
|
||||
And I wait until ".block_myoverview [data-control='next']" "css_element" exists
|
||||
And I click on "[data-control='next']" "css_element" in the "Course overview" "block"
|
||||
Then the "class" attribute of ".block_myoverview [data-control='next']" "css_element" should contain "disabled"
|
||||
And I log out
|
||||
|
||||
@@ -70,6 +70,10 @@ $CFG->dboptions = array(
|
||||
// can be removed for MySQL (by default it will
|
||||
// use 'utf8mb4_unicode_ci'. This option should
|
||||
// be removed for all other databases.
|
||||
// 'extrainfo' => [], // Extra information for the DB driver, e.g. SQL Server,
|
||||
// has additional configuration according to its environment,
|
||||
// which the administrator can specify to alter and
|
||||
// override any connection options.
|
||||
// 'fetchbuffersize' => 100000, // On PostgreSQL, this option sets a limit
|
||||
// on the number of rows that are fetched into
|
||||
// memory when doing a large recordset query
|
||||
|
||||
@@ -43,24 +43,24 @@ Feature: We can change what we are viewing on the grader report
|
||||
And I click on "Hide" "link" in the "Test assignment name 2" activity
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I should see "Test assignment name 1"
|
||||
And I should see "Test assignment name 2"
|
||||
And I should see "Test assignment name 1" in the "user-grades" "table"
|
||||
And I should see "Test assignment name 2" in the "user-grades" "table"
|
||||
And I should see "Manual grade"
|
||||
And I should see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -4- | -5- | -6- | -7- |
|
||||
| Student 1 | 80 | 90 | 30 | 170 |
|
||||
And I click on "Change to aggregates only" "link"
|
||||
And I should not see "Test assignment name 1"
|
||||
And I should not see "Test assignment name 2"
|
||||
And I should not see "Test assignment name 1" in the "user-grades" "table"
|
||||
And I should not see "Test assignment name 2" in the "user-grades" "table"
|
||||
And I should not see "Manual grade"
|
||||
And I should see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -4- |
|
||||
| Student 1 | 170 |
|
||||
And I click on "Change to grades only" "link"
|
||||
And I should see "Test assignment name 1"
|
||||
And I should see "Test assignment name 2"
|
||||
And I should see "Test assignment name 1" in the "user-grades" "table"
|
||||
And I should see "Test assignment name 2" in the "user-grades" "table"
|
||||
And I should see "Manual grade"
|
||||
And I should not see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
@@ -68,7 +68,7 @@ Feature: We can change what we are viewing on the grader report
|
||||
| Student 1 | 80 | 90 | 30 |
|
||||
|
||||
@javascript @skip_chrome_zerosize
|
||||
Scenario: View and minimise the grader report containing hidden activities without the 'moodle/grade:viewhidden' capability
|
||||
Scenario: Minimise the grader report containing hidden activities without the 'moodle/grade:viewhidden' capability
|
||||
When I am on "Course 1" course homepage with editing mode on
|
||||
And I open "Test assignment name 2" actions menu
|
||||
And I click on "Hide" "link" in the "Test assignment name 2" activity
|
||||
@@ -81,24 +81,24 @@ Feature: We can change what we are viewing on the grader report
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I should see "Test assignment name 1"
|
||||
And I should see "Test assignment name 2"
|
||||
And I should see "Test assignment name 1" in the "user-grades" "table"
|
||||
And I should see "Test assignment name 2" in the "user-grades" "table"
|
||||
And I should see "Manual grade"
|
||||
And I should see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -4- | -5- | -6- | -7- |
|
||||
| Student 1 | 80 | - | 30 | 105.71 |
|
||||
And I click on "Change to aggregates only" "link"
|
||||
And I should not see "Test assignment name 1"
|
||||
And I should not see "Test assignment name 2"
|
||||
And I should not see "Test assignment name 1" in the "user-grades" "table"
|
||||
And I should not see "Test assignment name 2" in the "user-grades" "table"
|
||||
And I should not see "Manual grade"
|
||||
And I should see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -4- |
|
||||
| Student 1 | 105.71 |
|
||||
And I click on "Change to grades only" "link"
|
||||
And I should see "Test assignment name 1"
|
||||
And I should see "Test assignment name 2"
|
||||
And I should see "Test assignment name 1" in the "user-grades" "table"
|
||||
And I should see "Test assignment name 2" in the "user-grades" "table"
|
||||
And I should see "Manual grade"
|
||||
And I should not see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
|
||||
+2
-1
@@ -1460,7 +1460,8 @@ $string['xmlrpcmnetenabled'] = 'It has been detected that the Moodle Networking
|
||||
$string['xmlrpcwebserviceenabled'] = 'It has been detected that the XML-RPC Web Service protocol is enabled on your site. This feature relies on the PHP XML-RPC extension which is no longer maintained by PHP.';
|
||||
$string['yuicomboloading'] = 'YUI combo loading';
|
||||
$string['ziprequired'] = 'The Zip PHP extension is now required by Moodle, info-ZIP binaries or PclZip library are not used anymore.';
|
||||
|
||||
$string['modassignmentinuse'] = 'Your site is still using the Assignment 2.2 plugin. Before upgrading you must 1) backup any Assignment 2.2 activities that you want to keep and restore them as Assignment activities, and 2) delete all Assignment 2.2 data from the database.';
|
||||
$string['modassignmentsubpluginsexist'] = 'Assignment 2.2. subplugins may be present. The mod/assignment folder and all of its subplugins need to be removed before upgrading.';
|
||||
|
||||
$string['caching'] = 'Caching';
|
||||
$string['cachesettings'] = 'Cache settings';
|
||||
|
||||
@@ -180,5 +180,5 @@ $string['XOF'] = 'CFA Franc BCEAO';
|
||||
$string['XPF'] = 'CFP Franc';
|
||||
$string['YER'] = 'Yemeni Rial';
|
||||
$string['ZAR'] = 'South African Rand';
|
||||
$string['ZMK'] = 'Zambian Kwacha';
|
||||
$string['ZMW'] = 'Zambian Kwacha';
|
||||
$string['ZWL'] = 'Zimbabwe Dollar';
|
||||
|
||||
@@ -53,6 +53,7 @@ $string['cutpastemozilla'] = 'Unfortunately, you cannot currently use normal key
|
||||
$string['delete'] = 'Delete';
|
||||
$string['editors'] = 'Text editors';
|
||||
$string['editorsettings'] = 'Manage editors';
|
||||
$string['editorxformat'] = '{$a} format';
|
||||
$string['enterurlfirst'] = 'You have to enter an URL first';
|
||||
$string['filebrowser'] = 'File Browser';
|
||||
$string['findwhat'] = 'Find';
|
||||
|
||||
@@ -666,7 +666,7 @@ class behat_config_util {
|
||||
[
|
||||
'capabilities' => [
|
||||
'extra_capabilities' => [
|
||||
'chromeOptions' => [
|
||||
'goog:chromeOptions' => [
|
||||
'args' => [
|
||||
'unlimited-storage',
|
||||
'disable-web-security',
|
||||
@@ -678,6 +678,16 @@ class behat_config_util {
|
||||
$values
|
||||
);
|
||||
|
||||
// Selenium no longer supports non-w3c browser control.
|
||||
// Rename chromeOptions to goog:chromeOptions, which is the W3C variant of this.
|
||||
if (array_key_exists('chromeOptions', $values['capabilities']['extra_capabilities'])) {
|
||||
$values['capabilities']['extra_capabilities']['goog:chromeOptions'] = array_merge_recursive(
|
||||
$values['capabilities']['extra_capabilities']['goog:chromeOptions'],
|
||||
$values['capabilities']['extra_capabilities']['chromeOptions']
|
||||
);
|
||||
unset($values['capabilities']['extra_capabilities']['chromeOptions']);
|
||||
}
|
||||
|
||||
// If the mobile app is enabled, check its version and add appropriate tags.
|
||||
if ($mobiletags = $this->get_mobile_version_tags()) {
|
||||
if (!empty($values['tags'])) {
|
||||
@@ -687,13 +697,13 @@ class behat_config_util {
|
||||
}
|
||||
}
|
||||
|
||||
$values['capabilities']['extra_capabilities']['chromeOptions']['args'] = array_map(function($arg): string {
|
||||
$values['capabilities']['extra_capabilities']['goog:chromeOptions']['args'] = array_map(function($arg): string {
|
||||
if (substr($arg, 0, 2) === '--') {
|
||||
return substr($arg, 2);
|
||||
}
|
||||
return $arg;
|
||||
}, $values['capabilities']['extra_capabilities']['chromeOptions']['args']);
|
||||
sort($values['capabilities']['extra_capabilities']['chromeOptions']['args']);
|
||||
}, $values['capabilities']['extra_capabilities']['goog:chromeOptions']['args']);
|
||||
sort($values['capabilities']['extra_capabilities']['goog:chromeOptions']['args']);
|
||||
}
|
||||
|
||||
// Fill tags information.
|
||||
|
||||
@@ -1676,4 +1676,30 @@ EOF;
|
||||
|
||||
return !empty($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user id from an identifier.
|
||||
*
|
||||
* The user username and email fields are checked.
|
||||
*
|
||||
* @param string $identifier The user's username or email.
|
||||
* @return int|null The user id or null if not found.
|
||||
*/
|
||||
protected function get_user_id_by_identifier(string $identifier): ?int {
|
||||
global $DB;
|
||||
|
||||
$sql = <<<EOF
|
||||
SELECT id
|
||||
FROM {user}
|
||||
WHERE username = :username
|
||||
OR email = :email
|
||||
EOF;
|
||||
|
||||
$result = $DB->get_field_sql($sql, [
|
||||
'username' => $identifier,
|
||||
'email' => $identifier,
|
||||
]);
|
||||
|
||||
return $result ?: null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,6 +242,10 @@ function cron_run_inner_scheduled_task(\core\task\task_base $task) {
|
||||
$predbqueries = null;
|
||||
$predbqueries = $DB->perf_get_queries();
|
||||
$pretime = microtime(1);
|
||||
|
||||
// Ensure that we have a clean session with the correct cron user.
|
||||
cron_setup_user();
|
||||
|
||||
try {
|
||||
get_mailer('buffer');
|
||||
cron_prepare_core_renderer();
|
||||
@@ -325,6 +329,10 @@ function cron_run_inner_adhoc_task(\core\task\adhoc_task $task) {
|
||||
}
|
||||
|
||||
cron_setup_user($user);
|
||||
} else {
|
||||
// No user specified, ensure that we have a clean session with the correct cron user.
|
||||
cron_setup_user();
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -208,21 +208,28 @@ class sqlsrv_native_moodle_database extends moodle_database {
|
||||
|
||||
$this->store_settings($dbhost, $dbuser, $dbpass, $dbname, $prefix, $dboptions);
|
||||
|
||||
$options = [
|
||||
'UID' => $this->dbuser,
|
||||
'PWD' => $this->dbpass,
|
||||
'Database' => $this->dbname,
|
||||
'CharacterSet' => 'UTF-8',
|
||||
'MultipleActiveResultSets' => true,
|
||||
'ConnectionPooling' => !empty($this->dboptions['dbpersist']),
|
||||
'ReturnDatesAsStrings' => true,
|
||||
];
|
||||
|
||||
$dbhost = $this->dbhost;
|
||||
if (!empty($dboptions['dbport'])) {
|
||||
$dbhost .= ',' . $dboptions['dbport'];
|
||||
}
|
||||
|
||||
$this->sqlsrv = sqlsrv_connect($dbhost, array
|
||||
(
|
||||
'UID' => $this->dbuser,
|
||||
'PWD' => $this->dbpass,
|
||||
'Database' => $this->dbname,
|
||||
'CharacterSet' => 'UTF-8',
|
||||
'MultipleActiveResultSets' => true,
|
||||
'ConnectionPooling' => !empty($this->dboptions['dbpersist']),
|
||||
'ReturnDatesAsStrings' => true,
|
||||
));
|
||||
// The sqlsrv_connect() has a lot of connection options to be used.
|
||||
// Users can add any supported options with the 'extrainfo' key in the dboptions.
|
||||
if (isset($this->dboptions['extrainfo'])) {
|
||||
$options = array_merge($options, $this->dboptions['extrainfo']);
|
||||
}
|
||||
|
||||
$this->sqlsrv = sqlsrv_connect($dbhost, $options);
|
||||
|
||||
if ($this->sqlsrv === false) {
|
||||
$this->sqlsrv = null;
|
||||
|
||||
@@ -21,7 +21,7 @@ Feature: Atto Autosave
|
||||
And I click on "Save changes" "button"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I set the field with xpath "//select[@name='summary_editor[format]']" to "1"
|
||||
And I set the field "Course summary format" to "1"
|
||||
And I click on "Save and display" "button"
|
||||
And I log out
|
||||
|
||||
|
||||
@@ -444,6 +444,7 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element implements templatab
|
||||
$context['id'] = $id;
|
||||
$context['value'] = $text;
|
||||
$context['format'] = $format;
|
||||
$context['formatlabel'] = get_string('editorxformat', 'editor', $this->_label);
|
||||
|
||||
if (!is_null($this->getAttribute('onblur')) && !is_null($this->getAttribute('onchange'))) {
|
||||
$context['changelistener'] = true;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
</div>
|
||||
<div>
|
||||
{{#hasformats}}
|
||||
<label for="menu{{name}}format" class="sr-only">{{formatlabel}}</label>
|
||||
<select name="{{name}}[format]" id="menu{{name}}format" class="custom-select">
|
||||
{{#formats}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{text}}</option>
|
||||
|
||||
@@ -702,7 +702,7 @@ abstract class advanced_testcase extends base_testcase {
|
||||
}
|
||||
|
||||
cron_prepare_core_renderer();
|
||||
$this->setUser($user);
|
||||
cron_setup_user($user);
|
||||
|
||||
$task->execute();
|
||||
\core\task\manager::adhoc_task_complete($task);
|
||||
|
||||
@@ -33,8 +33,13 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @category phpunit
|
||||
* @copyright 2012 Petr Skoda {@link http://skodak.org}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \advanced_testcase
|
||||
*/
|
||||
class core_phpunit_advanced_testcase extends advanced_testcase {
|
||||
public static function setUpBeforeClass(): void {
|
||||
global $CFG;
|
||||
require_once(__DIR__ . '/fixtures/adhoc_test_task.php');
|
||||
}
|
||||
|
||||
public function test_debugging() {
|
||||
global $CFG;
|
||||
@@ -680,4 +685,53 @@ class core_phpunit_advanced_testcase extends advanced_testcase {
|
||||
self::resetAllData(false);
|
||||
self::assertFalse(core_useragent::get_user_agent_string(), 'It should not be set again, data was reset.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::runAdhocTasks
|
||||
*/
|
||||
public function test_runadhoctasks_no_tasks_queued(): void {
|
||||
$this->runAdhocTasks();
|
||||
$this->expectOutputRegex('/^$/');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::runAdhocTasks
|
||||
*/
|
||||
public function test_runadhoctasks_tasks_queued(): void {
|
||||
$this->resetAfterTest(true);
|
||||
$admin = get_admin();
|
||||
\core\task\manager::queue_adhoc_task(new \core_phpunit\adhoc_test_task());
|
||||
$this->runAdhocTasks();
|
||||
$this->expectOutputRegex("/Task was run as {$admin->id}/");
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::runAdhocTasks
|
||||
*/
|
||||
public function test_runadhoctasks_with_existing_user_change(): void {
|
||||
$this->resetAfterTest(true);
|
||||
$admin = get_admin();
|
||||
|
||||
$this->setGuestUser();
|
||||
\core\task\manager::queue_adhoc_task(new \core_phpunit\adhoc_test_task());
|
||||
$this->runAdhocTasks();
|
||||
$this->expectOutputRegex("/Task was run as {$admin->id}/");
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::runAdhocTasks
|
||||
*/
|
||||
public function test_runadhoctasks_with_existing_user_change_and_specified(): void {
|
||||
global $USER;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
|
||||
$this->setGuestUser();
|
||||
$task = new \core_phpunit\adhoc_test_task();
|
||||
$task->set_userid($user->id);
|
||||
\core\task\manager::queue_adhoc_task($task);
|
||||
$this->runAdhocTasks();
|
||||
$this->expectOutputRegex("/Task was run as {$user->id}/");
|
||||
}
|
||||
}
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_phpunit;
|
||||
|
||||
/**
|
||||
* Fixtures for task tests.
|
||||
*
|
||||
* @package core
|
||||
* @category phpunit
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class adhoc_test_task extends \core\task\adhoc_task {
|
||||
/**
|
||||
* Execute.
|
||||
*/
|
||||
public function execute() {
|
||||
global $USER;
|
||||
mtrace("Task was run as {$USER->id}");
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -170,7 +170,11 @@ function get_moodle_cookie() {
|
||||
|
||||
/**
|
||||
* Sets up current user and course environment (lang, etc.) in cron.
|
||||
* Do not use outside of cron script!
|
||||
* Note: This function is intended only for use in:
|
||||
* - the cron runner scripts
|
||||
* - individual tasks which extend the adhoc_task and scheduled_task classes
|
||||
* - unit tests related to tasks
|
||||
* - other parts of the cron/task system
|
||||
*
|
||||
* @param stdClass $user full user object, null means default cron user (admin),
|
||||
* value 'reset' means reset internal static caches.
|
||||
|
||||
@@ -796,6 +796,8 @@ if (empty($CFG->sessiontimeout)) {
|
||||
$CFG->sessiontimeout = 8 * 60 * 60;
|
||||
}
|
||||
\core\session\manager::start();
|
||||
// Prevent ignoresesskey hack from getting carried over to a next page.
|
||||
unset($USER->ignoresesskey);
|
||||
|
||||
// Set default content type and encoding, developers are still required to use
|
||||
// echo $OUTPUT->header() everywhere, anything that gets set later should override these headers.
|
||||
|
||||
@@ -1526,4 +1526,27 @@ class upgradelib_test extends advanced_testcase {
|
||||
$this->assertEquals('admin_dir_usage', $result->getInfo());
|
||||
$this->assertFalse($result->getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the check_mod_assignment check if mod_assignment is still used.
|
||||
*
|
||||
* @covers ::check_mod_assignment
|
||||
* @return void
|
||||
*/
|
||||
public function test_check_mod_assignment_is_used(): void {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$result = new environment_results('custom_checks');
|
||||
|
||||
if ($DB->get_manager()->table_exists('assignment')) {
|
||||
$DB->insert_record('assignment', (object)['name' => 'test_assign', 'intro' => 'test_assign_intro']);
|
||||
|
||||
$this->assertNotNull(check_mod_assignment($result));
|
||||
$this->assertEquals('Assignment 2.2 is in use', $result->getInfo());
|
||||
$this->assertFalse($result->getStatus());
|
||||
} else {
|
||||
$this->assertTrue($result->getStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
===3.9.21===
|
||||
* Added 'extrainfo' in the DB options config. Its extra information for the DB driver, e.g. SQL Server,
|
||||
has additional configuration according to its environment, which the administrator can specify to alter and
|
||||
override any connection options.
|
||||
|
||||
===3.9.12===
|
||||
* Two new helper functions have been added to lib/datalib.php, for safely preparing SQL ORDER BY statements where user
|
||||
interactions define sort parameters (see the respective docblocks for full details and examples):
|
||||
|
||||
+27
-1
@@ -614,7 +614,7 @@ function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
|
||||
|
||||
// Throw exception if plugin is incompatible with moodle version.
|
||||
if (!empty($plugin->incompatible)) {
|
||||
if ($CFG->branch <= $plugin->incompatible) {
|
||||
if ($CFG->branch >= $plugin->incompatible) {
|
||||
throw new plugin_incompatible_exception($component, $plugin->version);
|
||||
}
|
||||
}
|
||||
@@ -2766,3 +2766,29 @@ function check_xmlrpc_usage(environment_results $result): ?environment_results {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the mod_assignment is currently being used.
|
||||
*
|
||||
* @param environment_results $result
|
||||
* @return environment_results|null
|
||||
*/
|
||||
function check_mod_assignment(environment_results $result): ?environment_results {
|
||||
global $DB, $CFG;
|
||||
|
||||
// Check the number of records.
|
||||
if ($DB->get_manager()->table_exists('assignment') && $DB->count_records('assignment') > 0) {
|
||||
$result->setInfo('Assignment 2.2 is in use');
|
||||
$result->setFeedbackStr('modassignmentinuse');
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Check for mod_assignment subplugins.
|
||||
if (is_dir($CFG->dirroot . '/mod/assignment/type')) {
|
||||
$result->setInfo('Assignment 2.2 subplugins present');
|
||||
$result->setFeedbackStr('modassignmentsubpluginsexist');
|
||||
return $result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ Feature: To be able to see and save user message preferences as admin
|
||||
And I navigate to "Messaging > Notification settings" in site administration
|
||||
And I set the field "email" to "1"
|
||||
And I press "Save changes"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I click on "Student 1" "link" in the "Student 1" "table_row"
|
||||
And I am on the "student1" "user > profile" page
|
||||
And I click on "Preferences" "link" in the "#region-main-box" "css_element"
|
||||
And I click on "Message preferences" "link" in the "#region-main-box" "css_element"
|
||||
And I click on "//label[@data-state='loggedoff']" "xpath_element"
|
||||
|
||||
@@ -77,8 +77,6 @@ class mod_resource_generator extends testing_module_generator {
|
||||
}
|
||||
$usercontext = context_user::instance($USER->id);
|
||||
$filename = $record->defaultfilename ?? 'resource' . ($this->instancecount + 1) . '.txt';
|
||||
// Set filepath depending on filename.
|
||||
$filepath = (isset($record->defaultfilename)) ? $CFG->dirroot . '/' : '/';
|
||||
|
||||
// Pick a random context id for specified user.
|
||||
$record->files = file_get_unused_draft_itemid();
|
||||
@@ -86,11 +84,22 @@ class mod_resource_generator extends testing_module_generator {
|
||||
// Add actual file there.
|
||||
$filerecord = ['component' => 'user', 'filearea' => 'draft',
|
||||
'contextid' => $usercontext->id, 'itemid' => $record->files,
|
||||
'filename' => basename($filename), 'filepath' => $filepath];
|
||||
'filename' => basename($filename), 'filepath' => '/'];
|
||||
$fs = get_file_storage();
|
||||
if ($record->uploaded == 1) {
|
||||
// For uploading a file, it's required to specify a file, how not!
|
||||
if (!isset($record->defaultfilename)) {
|
||||
throw new coding_exception(
|
||||
'The $record->defaultfilename option is required in order to upload a file');
|
||||
}
|
||||
// We require the full file path to exist when uploading a real file (fixture or whatever).
|
||||
$fullfilepath = $CFG->dirroot . '/' . $record->defaultfilename;
|
||||
if (!is_readable($fullfilepath)) {
|
||||
throw new coding_exception(
|
||||
'The $record->defaultfilename option must point to an existing file within dirroot');
|
||||
}
|
||||
// Create file using pathname (defaultfilename) set.
|
||||
$fs->create_file_from_pathname($filerecord, $filepath . $filename);
|
||||
$fs->create_file_from_pathname($filerecord, $fullfilepath);
|
||||
} else {
|
||||
// If defaultfilename is not set, create file from string "resource 1.txt".
|
||||
$fs->create_file_from_string($filerecord, 'Test resource ' . $filename . ' file');
|
||||
@@ -98,6 +107,6 @@ class mod_resource_generator extends testing_module_generator {
|
||||
}
|
||||
|
||||
// Do work to actually add the instance.
|
||||
return parent::create_instance($record, (array)$options);
|
||||
return parent::create_instance($record, $options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,12 @@ defined('MOODLE_INTERNAL') || die();
|
||||
*
|
||||
* @package mod_resource
|
||||
* @category phpunit
|
||||
* @covers \mod_resource_generator
|
||||
* @copyright 2013 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_resource_generator_testcase extends advanced_testcase {
|
||||
|
||||
public function test_generator() {
|
||||
global $DB, $SITE;
|
||||
|
||||
@@ -86,5 +88,46 @@ class mod_resource_generator_testcase extends advanced_testcase {
|
||||
$this->assertCount(1, $files);
|
||||
$this->assertEquals('myfile.pdf', $file->get_filename());
|
||||
$this->assertEquals('Test resource myfile.pdf file', $file->get_content());
|
||||
|
||||
// Create a new resource uploading a file.
|
||||
$resource = $generator->create_instance([
|
||||
'course' => $SITE->id,
|
||||
'uploaded' => true,
|
||||
'defaultfilename' => 'mod/resource/tests/fixtures/samplefile.txt',
|
||||
]);
|
||||
|
||||
// Check that generated resource module contains the uploaded samplefile.txt.
|
||||
$cm = get_coursemodule_from_instance('resource', $resource->id);
|
||||
$context = \context_module::instance($cm->id);
|
||||
$files = $fs->get_area_files($context->id, 'mod_resource', 'content', false, '', false);
|
||||
$file = array_values($files)[0];
|
||||
$this->assertCount(1, $files);
|
||||
$this->assertEquals('samplefile.txt', $file->get_filename());
|
||||
$this->assertEquals('Hello!', $file->get_content());
|
||||
|
||||
// Try to generate a resource with uploaded file without specifying the file.
|
||||
try {
|
||||
$resource = $generator->create_instance([
|
||||
'course' => $SITE->id,
|
||||
'uploaded' => true,
|
||||
]);
|
||||
$this->assertTrue(false, 'coding_exception expected, defaultfilename is required');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf(\coding_exception::class, $e);
|
||||
$this->assertStringContainsString('defaultfilename option is required', $e->getMessage());
|
||||
}
|
||||
|
||||
// Try to generate a resource with uploaded file pointing to non-existing file.
|
||||
try {
|
||||
$resource = $generator->create_instance([
|
||||
'course' => $SITE->id,
|
||||
'uploaded' => true,
|
||||
'defaultfilename' => 'mod/resource/tests/fixtures/doesnotexist.txt',
|
||||
]);
|
||||
$this->assertTrue(false, 'coding_exception expected, defaultfilename must point to an existing file');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf(\coding_exception::class, $e);
|
||||
$this->assertStringContainsString('defaultfilename option must point to an existing file', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,15 +467,17 @@ class mod_wiki_external extends external_api {
|
||||
throw new moodle_exception('cannotviewpage', 'wiki');
|
||||
} else if ($subwiki->id != -1) {
|
||||
|
||||
// Set sort param.
|
||||
$options = $params['options'];
|
||||
if (!empty($options['sortby'])) {
|
||||
if ($options['sortdirection'] != 'ASC' && $options['sortdirection'] != 'DESC') {
|
||||
// Invalid sort direction. Use default.
|
||||
$options['sortdirection'] = 'ASC';
|
||||
}
|
||||
$sort = $options['sortby'] . ' ' . $options['sortdirection'];
|
||||
}
|
||||
|
||||
// Set sort param.
|
||||
$sort = get_safe_orderby([
|
||||
'id' => 'id',
|
||||
'title' => 'title',
|
||||
'timecreated' => 'timecreated',
|
||||
'timemodified' => 'timemodified',
|
||||
'pageviews' => 'pageviews',
|
||||
'default' => 'title',
|
||||
], $options['sortby'], $options['sortdirection'], false);
|
||||
|
||||
$pages = wiki_get_page_list($subwiki->id, $sort);
|
||||
$caneditpages = wiki_user_can_edit($subwiki);
|
||||
|
||||
@@ -21,9 +21,9 @@ Feature: Teachers can embed images into instructions and conclusion fields
|
||||
| workshop | C1 | Workshop with embedded images |
|
||||
And I am on the "Workshop with embedded images" "workshop activity editing" page logged in as admin
|
||||
And I set the following fields to these values:
|
||||
| instructauthorseditor[format] | 1 |
|
||||
| instructreviewerseditor[format] | 1 |
|
||||
| conclusioneditor[format] | 1 |
|
||||
| Instructions for submission format | 1 |
|
||||
| Instructions for assessment format | 1 |
|
||||
| Conclusion format | 1 |
|
||||
And I press "Save and display"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
|
||||
Generated
+472
-166
File diff suppressed because it is too large
Load Diff
+2
-4
@@ -4,11 +4,13 @@
|
||||
"description": "Moodle",
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.17.5",
|
||||
"@babel/eslint-parser": "^7.21.3",
|
||||
"@babel/plugin-proposal-class-properties": "7.16.7",
|
||||
"@babel/plugin-proposal-json-strings": "7.16.7",
|
||||
"@babel/plugin-syntax-dynamic-import": "7.8.3",
|
||||
"@babel/plugin-syntax-import-meta": "7.10.4",
|
||||
"@babel/preset-env": "7.16.11",
|
||||
"@xmldom/xmldom": "^0.8.7",
|
||||
"ajv": "8.10.0",
|
||||
"async": "3.2.3",
|
||||
"babel-eslint": "10.1.0",
|
||||
@@ -37,13 +39,9 @@
|
||||
"stylelint": "13.3.3",
|
||||
"stylelint-checkstyle-formatter": "0.1.2",
|
||||
"stylelint-csstree-validator": "1.8.0",
|
||||
"xmldom": "^0.6.0",
|
||||
"xpath": "0.0.32"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.14.0 <17"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/eslint-parser": "^7.17.0"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@ Acknowledgments: https://moodle.org/security/
|
||||
Preferred-Languages: en
|
||||
Canonical: https://moodle.org/.well-known/security.txt
|
||||
Policy: https://moodledev.io/general/development/process/security
|
||||
Expires: 2023-05-29T01:00:00.000Z
|
||||
Expires: 2023-10-30T01:00:00.000Z
|
||||
|
||||
@@ -84,4 +84,29 @@ class behat_user extends behat_base {
|
||||
throw new ExpectationException('The "' . $field . '" field does have purpose "' . $purpose . '"', $this->getSession());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert page names to URLs for steps like 'When I am on the "[identifier]" "[page type]" page'.
|
||||
*
|
||||
* Recognised page names are:
|
||||
* | Page Type | Identifier meaning | Description |
|
||||
* | profile | username or email | User profile page (/user/profile.php) |
|
||||
*
|
||||
* @param string $type identifies which type of page this is, e.g. 'Editing'.
|
||||
* @param string $identifier identifies the user, e.g. 'student1'.
|
||||
* @return moodle_url the corresponding URL.
|
||||
* @throws Exception with a meaningful error message if the specified page cannot be found.
|
||||
*/
|
||||
protected function resolve_page_instance_url(string $type, string $identifier): moodle_url {
|
||||
switch (strtolower($type)) {
|
||||
case 'profile':
|
||||
$userid = $this->get_user_id_by_identifier($identifier);
|
||||
if (!$userid) {
|
||||
throw new Exception('The specified user with username or email "' . $identifier . '" does not exist');
|
||||
}
|
||||
return new moodle_url('/user/profile.php', ['id' => $userid]);
|
||||
default:
|
||||
throw new Exception("Unrecognised page type '{$type}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,8 +76,7 @@ Feature: The student can navigate to their grades page and user grade report.
|
||||
| moodle/user:viewuseractivitiesreport | 1 |
|
||||
| moodle/user:viewdetails | 1 |
|
||||
And I click on "Create this role" "button"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I follow "Student 1"
|
||||
And I am on the "student1" "user > profile" page
|
||||
And I click on "Preferences" "link" in the ".profile_tree" "css_element"
|
||||
And I follow "Assign roles relative to this user"
|
||||
And I follow "Parent"
|
||||
|
||||
@@ -68,8 +68,7 @@ Feature: Access to preferences page
|
||||
| moodle/user:viewuseractivitiesreport | 1 |
|
||||
| moodle/user:viewdetails | 1 |
|
||||
And I click on "Create this role" "button"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I follow "Student 1"
|
||||
And I am on the "student1" "user > profile" page
|
||||
And I click on "Preferences" "link" in the ".profile_tree" "css_element"
|
||||
And I follow "Assign roles relative to this user"
|
||||
And I follow "Parent"
|
||||
|
||||
+2
-2
@@ -29,9 +29,9 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2020061520.00; // 20200615 = branching date YYYYMMDD - do not modify!
|
||||
$version = 2020061521.00; // 20200615 = branching date YYYYMMDD - do not modify!
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '3.9.20 (Build: 20230313)'; // Human-friendly version name
|
||||
$release = '3.9.21 (Build: 20230424)'; // Human-friendly version name
|
||||
$branch = '39'; // This version's branch.
|
||||
$maturity = MATURITY_STABLE; // This version's maturity level.
|
||||
|
||||
Reference in New Issue
Block a user