Compare commits

..

43 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) 0ec02c2a67 Moodle release 3.9.10 2021-09-12 12:37:18 +02:00
Eloy Lafuente (stronk7) 8a709503ac weekly release 3.9.9+ 2021-09-11 12:12:28 +02:00
Eloy Lafuente (stronk7) 2c7f5745c6 Merge branch 'install_39_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_39_STABLE 2021-09-11 12:12:27 +02:00
Shamim Rezaie 9a18af46d7 MDL-71240 filter_tex: Add allowlist for filter_tex_sanitize_formula 2021-09-10 18:10:52 +02:00
Jun Pataleta e09160b6db Merge branch 'MDL-72494_39' of https://github.com/stronk7/moodle into MOODLE_39_STABLE 2021-09-10 23:09:22 +08:00
Mikel Martín 884a9b9706 MDL-72494 theme_boost: Use 'scroll-margin-top' for anchor links
Current anchor link offset fix is not working with 'display:flex' elements

Note this is a backport of MDL-71152 exclusively to 39_STABLE because
the original issue already has been applied to 310, 311 and master.

And seems to workaround a bug in Chrome 93 that is hitting Moodle.
2021-09-10 15:31:26 +02:00
AMOS bot 753b2fb53e Automatically generated installer lang files 2021-09-09 00:07:41 +00:00
AMOS bot 7806835569 Automatically generated installer lang files 2021-09-07 00:07:43 +00:00
Paul Holden a937101b06 MDL-71726 course: respect user access when exporting participants.
We should ensure that users being exported are enrolled on the
course being exported from. In courses where the current user can't
access all groups we should ensure that users being exported belong
to the same groups as them.
2021-09-03 17:07:40 +02:00
Sujith Haridasan 8596b6a299 MDL-71160 auth_db: Use strict comaprison
Use strict comparison to avoid type juggling.

Signed-off-by: Sujith Haridasan <sujith@moodle.com>
2021-09-03 17:07:40 +02:00
Paul Holden b5c8188961 MDL-71976 auth_shibboleth: consistent session parsing during logout. 2021-09-03 17:07:40 +02:00
Shamim Rezaie ed3ee9dd5c MDL-71240 filter_tex: Sanitize the whole latex document
LaTeX documents have a preamble section and admins can use a \newcommand
statement to define new commands there (or to give an alias to another
command). This commit makes sure no blocked command can escape
sanitization by being used in a new seemingly harmless command that is
defined in the LaTeX preamble.
2021-09-03 17:07:40 +02:00
Shamim Rezaie 87aaffc3d1 MDL-71240 filter_tex: Support paranoid mode for openin_any in latex 2021-09-03 17:07:40 +02:00
Huong Nguyen 4fae57fc97 MDL-71797 quiz: Improve the checks when fetching user's attempts 2021-09-03 17:07:40 +02:00
Eloy Lafuente (stronk7) 9b9237fde1 Merge branch 'MDL-72478-39' of git://github.com/sarjona/moodle into MOODLE_39_STABLE 2021-09-03 17:03:32 +02:00
Sara Arjona 6f3450ef1e MDL-72478 calendar: Fix PHPUnit failure with offset
Before PHP 8.0.10, the time is lost when datetime->modify() is used
with weekdays. However, with PHP 8.0.10, the time is kept.
In consequence, the test_yearly_every_20th_monday_forever method
started failing.
For fixing it, the offset has been removed and the time has been set
to 00:00, so the behaviour will be the same regardless the PHP
version.
2021-09-03 09:35:11 +02:00
Sara Arjona 089f5bb0ec weekly release 3.9.9+ 2021-09-02 11:51:29 +02:00
Jun Pataleta 0391a4afc7 Merge branch 'MDL-72440_39' of https://github.com/stronk7/moodle into MOODLE_39_STABLE 2021-09-02 09:52:20 +08:00
Eloy Lafuente (stronk7) 0b26fce0b6 MDL-72440 js: reconcile npm installed stuff
When npm-shrinkwrap.json was regenerated few days ago by MDL-72014
running audit-fix on it, it seems that some checksums in the "lodash"
package were missing.

Now they are properly set and that's leading to npm-shrinkwrap.json
changes when people runs npm install (note npm ci is the recommended
way to install all the dev dependencies).

So, just reconcile the file to include the new checksums.
2021-08-31 11:22:16 +02:00
Andrew Nicols 361070ef5d weekly release 3.9.9+ 2021-08-27 12:00:30 +08:00
Andrew Nicols 81cb18a67c Merge branch 'install_39_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_39_STABLE 2021-08-27 12:00:29 +08:00
Heena Agheda f4b92ca799 MDL-72187 logstore: record log store's visibility change 2021-08-26 12:57:38 +08:00
sam marshall e563d32ca2 MDL-72152 Behat: No way to test key shortcuts with letter keys
Extends the existing step 'And I press the Shift Left key' so that
it supports letter/other keys: 'And I press the Ctrl C key'.
2021-08-26 11:37:27 +08:00
Andrew Nicols 2575add511 Merge branch 'MDL-72312_39' of https://github.com/stronk7/moodle into MOODLE_39_STABLE 2021-08-26 11:28:34 +08:00
AMOS bot 61b3c4b453 Automatically generated installer lang files 2021-08-26 00:07:45 +00:00
Andrew Nicols d82d2bd6d6 Merge branch 'MDL-72014_39' of https://github.com/stronk7/moodle into MOODLE_39_STABLE 2021-08-24 09:17:17 +08:00
Eloy Lafuente (stronk7) a7a8db38aa Merge branch 'MDL-71055-39' of git://github.com/andrewnicols/moodle into MOODLE_39_STABLE 2021-08-23 23:22:51 +02:00
Eloy Lafuente (stronk7) a4e45e8159 MDL-72312 environment: Add new optional custom check for igbinary
This optional environmental check will look if:

- the site is running php72.
- the site has igbinary extension enabled.
- the igbinary extension version is a buggy one >=3.2.2 <= 3.2.4
- the bug is reproducible.

And will warn if all the conditions are met.
2021-08-23 15:50:18 +02:00
Eloy Lafuente (stronk7) 814c80da13 MDL-72312 GHA: Force use of igbinary working version
And also remove memcached and redis that have dependencies on it.

Versions 3.2.2 - 3.2.4 have a bug returning
arrays with index messed up. This affects
key() and next() operations when reading
information serialised with igbinary.

Notably Moodle's MUC uses igbinary when
available and was leading to some wrong
operations and test failures.

Once a fixed version is used by GHA this
can be reverted. See MDL-72399.

Note this only affects to php72, newer php
versions are not affected.
2021-08-23 15:49:59 +02:00
Andrew Nicols f7ffb41db4 MDL-71055 behat: Update core settings to use generator
These changes have only been applied to settings which were already
using settings names and values, but which were still using the UI.
2021-08-23 12:47:22 +08:00
AMOS bot c9efe1b1ac Automatically generated installer lang files 2021-08-18 00:07:41 +00:00
AMOS bot 82c845d8d3 Automatically generated installer lang files 2021-08-14 00:07:43 +00:00
Eloy Lafuente (stronk7) 30da75a460 MDL-72014 nodejs: audit fix to solve some security reports
Simply run npm audit fix that updates these main packages:

- xmldom 0.6.0
- grunt 1.4.1
- gherkin-lint 4.2.2

(and also a bunch of dependencies)
2021-08-12 20:07:10 +02:00
Ilya Tregubov fdb7aa8035 weekly release 3.9.9+ 2021-08-12 16:50:21 +02:00
Ilya Tregubov 4e14e2631c Merge branch 'install_39_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_39_STABLE 2021-08-12 16:50:20 +02:00
Eloy Lafuente (stronk7) 2ae147c9af Merge branch 'MDL-72265_39' of https://github.com/timhunt/moodle into MOODLE_39_STABLE 2021-08-12 00:06:21 +02:00
AMOS bot 6cacc0a4a3 Automatically generated installer lang files 2021-08-06 00:07:47 +00:00
Víctor Déniz c66c1a04b5 weekly release 3.9.9+ 2021-08-05 16:27:35 +01:00
Víctor Déniz 06001d9c9d Merge branch 'install_39_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_39_STABLE 2021-08-05 16:27:34 +01:00
Tim Hunt 9f01ded64e MDL-72265 backup: fix checking of override capabilites on restore
Thanks to Peter Dias <peter@moodle.com> for his help with the unit test.
2021-08-05 15:50:31 +01:00
Víctor Déniz 7bd088e443 Merge branch 'MDL-72262-39' of git://github.com/ilyatregubov/moodle into MOODLE_39_STABLE 2021-08-04 12:44:23 +01:00
Ilya Tregubov f67020d1c2 MDL-72262 behat: Make alias shorter to fix Oracle failures. 2021-08-02 08:26:50 +02:00
AMOS bot 2bc1e50886 Automatically generated installer lang files 2021-07-31 00:07:46 +00:00
55 changed files with 1425 additions and 713 deletions
+8
View File
@@ -55,9 +55,16 @@ jobs:
include:
- os: ubuntu-18.04
php: 7.2
# Need to disable both redis and memcached (both are optional) in order to keep igbinary installed.
# (there are dependencies that become broken if we just switch the igbinary version).
# Need to do this for php 7.2 because of a bug with current default igbinary
# versions used by GHA being >= 3.2.2 and <= 3.2.4 (buggy ones).
# TODO: MDL-72399 - Revert this patch once igbinary 3.2.5 or up is the default @ GHA.
extensions: :redis, :memcached, igbinary-3.2.6
db: mysqli
- os: ubuntu-18.04
php: 7.4
extensions:
db: pgsql
steps:
@@ -88,6 +95,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: ${{ matrix.extensions }}
coverage: none
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
+10
View File
@@ -3163,6 +3163,11 @@
<ON_CHECK message="sixtyfourbitswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_igbinary322_version" level="optional">
<FEEDBACK>
<ON_CHECK message="igbinary322buggyversion" />
</FEEDBACK>
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="3.10" requires="3.5">
@@ -3345,6 +3350,11 @@
<ON_CHECK message="sixtyfourbitswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_igbinary322_version" level="optional">
<FEEDBACK>
<ON_CHECK message="igbinary322buggyversion" />
</FEEDBACK>
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="3.11" requires="3.6">
+2 -5
View File
@@ -53,11 +53,8 @@ class behat_admin extends behat_base {
}
foreach ($data as $label => $value) {
$this->execute('behat_navigation::i_select_from_flat_navigation_drawer', [get_string('administrationsite')]);
// Search by label.
$this->execute('behat_forms::i_set_the_field_to', [get_string('query', 'admin'), $label]);
$this->execute("behat_forms::press_button", get_string('search', 'admin'));
// Navigate straight to the search results fo rthis label.
$this->execute('behat_general::i_visit', ["/admin/search.php?query=" . urlencode($label)]);
// Admin settings does not use the same DOM structure than other moodle forms
// but we also need to use lib/behat/form_field/* to deal with the different moodle form elements.
@@ -9,10 +9,8 @@ Feature: Manage data requests
| username | firstname | lastname | email |
| student1 | John | Doe | s1@example.com |
| student2 | Jane | Doe | s2@example.com |
And I log in as "admin"
And I set the following administration settings values:
| contactdataprotectionofficer | 1 |
And I log out
And the following config values are set as admin:
| contactdataprotectionofficer | 1 | tool_dataprivacy |
@javascript
Scenario: Marking general enquiries as complete
+2
View File
@@ -50,6 +50,7 @@ switch ($action) {
case 'disable':
unset($enabled[$enrol]);
set_config('enabled_stores', implode(',', array_keys($enabled)), 'tool_log');
add_to_config_log('tool_logstore_visibility', '1', '0', $enrol);
break;
case 'enable':
@@ -59,6 +60,7 @@ switch ($action) {
$enabled = array_keys($enabled);
$enabled[] = $enrol;
set_config('enabled_stores', implode(',', $enabled), 'tool_log');
add_to_config_log('tool_logstore_visibility', '0', '1', $enrol);
break;
case 'up':
@@ -0,0 +1,19 @@
@tool_log @report @report_configlog
Feature: In a report, admin can see logstore visibility changes
# Change log stores visibility so the report contains known data.
Background:
Given I log in as "admin"
And the following config values are set as admin:
| enabled_stores | logstore_standard | tool_log |
@javascript
Scenario: Display configuration changes report
When I navigate to "Plugins > Logging > Manage log stores" in site administration
And I click on "Disable" "icon" in the "Standard log" "table_row"
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 "report-configlog-report-table" table:
| User | Plugin | Setting | New value | Original value |
| Admin User | logstore_standard | tool_logstore_visibility | 0 | 1 |
| Admin User | logstore_database | tool_logstore_visibility | 1 | 0 |
+3 -3
View File
@@ -131,11 +131,11 @@ class auth_plugin_db extends auth_plugin_base {
$authdb->Close();
if ($this->config->passtype === 'plaintext') {
return ($fromdb == $extpassword);
return ($fromdb === $extpassword);
} else if ($this->config->passtype === 'md5') {
return (strtolower($fromdb) == md5($extpassword));
return (strtolower($fromdb) === md5($extpassword));
} else if ($this->config->passtype === 'sha1') {
return (strtolower($fromdb) == sha1($extpassword));
return (strtolower($fromdb) === sha1($extpassword));
} else if ($this->config->passtype === 'saltedcrypt') {
return password_verify($extpassword, $fromdb);
} else {
+16
View File
@@ -335,12 +335,28 @@ class auth_db_testcase extends advanced_testcase {
$DB->update_record('auth_db_users', $user3);
$this->assertTrue($auth->user_login('u3', 'heslo'));
// Test user created to see if the checking happens strictly.
$usermd5 = (object)['name' => 'usermd5', 'pass' => '0e462097431906509019562988736854'];
$usermd5->id = $DB->insert_record('auth_db_users', $usermd5);
// md5('240610708') === '0e462097431906509019562988736854'.
$this->assertTrue($auth->user_login('usermd5', '240610708'));
$this->assertFalse($auth->user_login('usermd5', 'QNKCDZO'));
set_config('passtype', 'sh1', 'auth_db');
$auth->config->passtype = 'sha1';
$user3->pass = sha1('heslo');
$DB->update_record('auth_db_users', $user3);
$this->assertTrue($auth->user_login('u3', 'heslo'));
// Test user created to see if the checking happens strictly.
$usersha1 = (object)['name' => 'usersha1', 'pass' => '0e66507019969427134894567494305185566735'];
$usersha1->id = $DB->insert_record('auth_db_users', $usersha1);
// sha1('aaroZmOk') === '0e66507019969427134894567494305185566735'.
$this->assertTrue($auth->user_login('usersha1', 'aaroZmOk'));
$this->assertFalse($auth->user_login('usersha1', 'aaK1STfY'));
set_config('passtype', 'saltedcrypt', 'auth_db');
$auth->config->passtype = 'saltedcrypt';
$user3->pass = password_hash('heslo', PASSWORD_BCRYPT);
+6 -7
View File
@@ -93,13 +93,12 @@ class helper {
foreach ($sessions as $session) {
// Get user session from DB.
if (session_decode(base64_decode($session->sessdata))) {
if (isset($_SESSION['SESSION']) && isset($_SESSION['SESSION']->shibboleth_session_id)) {
// If there is a match, kill the session.
if ($_SESSION['SESSION']->shibboleth_session_id == trim($spsessionid)) {
// Delete this user's sessions.
\core\session\manager::kill_user_sessions($session->userid);
}
$usersession = self::unserializesession(base64_decode($session->sessdata));
if (isset($usersession['SESSION']) && isset($usersession['SESSION']->shibboleth_session_id)) {
// If there is a match, kill the session.
if ($usersession['SESSION']->shibboleth_session_id == trim($spsessionid)) {
// Delete this user's sessions.
\core\session\manager::kill_user_sessions($session->userid);
}
}
}
+1 -3
View File
@@ -41,10 +41,8 @@ Feature: Authentication
Then I should see "You are not logged in" in the "page-footer" "region"
Scenario Outline: Checking the display of the Remember username checkbox
Given I log in as "admin"
And I set the following administration settings values:
Given the following config values are set as admin:
| rememberusername | <settingvalue> |
And I log out
And I am on homepage
When I click on "Log in" "link" in the ".logininfo" "css_element"
Then I should <expect> "Remember username"
@@ -358,6 +358,15 @@ class backup_controller extends base_controller {
return $this->plan;
}
/**
* For debug only. Get a simple test display of all the settings.
*
* @return string
*/
public function debug_display_all_settings_values(): string {
return $this->get_plan()->debug_display_all_settings_values();
}
/**
* Sets the user roles that should be kept in the destination course
* for a course copy operation.
@@ -350,6 +350,15 @@ class restore_controller extends base_controller {
}
}
/**
* For debug only. Get a simple test display of all the settings.
*
* @return string
*/
public function debug_display_all_settings_values(): string {
return $this->get_plan()->debug_display_all_settings_values();
}
public function get_info() {
return $this->info;
}
+2 -3
View File
@@ -2110,7 +2110,6 @@ class restore_ras_and_caps_structure_step extends restore_structure_step {
public function process_override($data) {
$data = (object)$data;
// Check roleid is one of the mapped ones
$newrole = $this->get_mapping('role', $data->roleid);
$newroleid = $newrole->newitemid ?? false;
@@ -2128,8 +2127,8 @@ class restore_ras_and_caps_structure_step extends restore_structure_step {
// Check if the new role is an overrideable role AND if the user performing the restore has the
// capability to assign the capability.
if (in_array($newrole->info['shortname'], $overrideableroles) &&
($safecapability && has_capability('moodle/role:safeoverride', $context, $userid) ||
!$safecapability && has_capability('moodle/role:override', $context, $userid))
(has_capability('moodle/role:override', $context, $userid) ||
($safecapability && has_capability('moodle/role:safeoverride', $context, $userid)))
) {
assign_capability($data->capability, $data->permission, $newroleid, $this->task->get_contextid());
} else {
+179
View File
@@ -0,0 +1,179 @@
<?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/>.
defined('MOODLE_INTERNAL') || die();
// Include all the needed stuff.
global $CFG;
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
/**
* Unit tests for how backup and restore handles role-related things.
*
* @package core_backup
* @copyright 2021 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class roles_backup_restore_test extends advanced_testcase {
/**
* Create a course where the (non-editing) Teacher role is overridden
* to have 'moodle/user:loginas' and 'moodle/site:accessallgroups'.
*
* @return stdClass the new course.
*/
protected function create_course_with_role_overrides(): stdClass {
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$teacher = $generator->create_user();
$context = context_course::instance($course->id);
$generator->enrol_user($teacher->id, $course->id, 'teacher');
$editingteacherrole = $this->get_role('teacher');
role_change_permission($editingteacherrole->id, $context, 'moodle/user:loginas', CAP_ALLOW);
role_change_permission($editingteacherrole->id, $context, 'moodle/site:accessallgroups', CAP_ALLOW);
return $course;
}
/**
* Get the role id from a shortname.
*
* @param string $shortname the role shortname.
* @return stdClass the role from the DB.
*/
protected function get_role(string $shortname): stdClass {
global $DB;
return $DB->get_record('role', ['shortname' => $shortname]);
}
/**
* Get an array capability => CAP_... constant for all the orverrides set for a given role on a given context.
*
* @param string $shortname role shortname.
* @param context $context context.
* @return array the overrides set here.
*/
protected function get_overrides_for_role_on_context(string $shortname, context $context): array {
$overridedata = get_capabilities_from_role_on_context($this->get_role($shortname), $context);
$overrides = [];
foreach ($overridedata as $override) {
$overrides[$override->capability] = $override->permission;
}
return $overrides;
}
/**
* Makes a backup of the course.
*
* @param stdClass $course The course object.
* @return string Unique identifier for this backup.
*/
protected function backup_course(\stdClass $course): string {
global $CFG, $USER;
// Turn off file logging, otherwise it can't delete the file (Windows).
$CFG->backup_file_logger_level = backup::LOG_NONE;
// Do backup with default settings. MODE_IMPORT means it will just
// create the directory and not zip it.
$bc = new \backup_controller(backup::TYPE_1COURSE, $course->id,
backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_IMPORT,
$USER->id);
$backupid = $bc->get_backupid();
$bc->execute_plan();
$bc->destroy();
return $backupid;
}
/**
* Restores a backup that has been made earlier.
*
* @param string $backupid The unique identifier of the backup.
* @param string $asroleshortname Which role in the new cousre the restorer should have.
* @return int The new course id.
*/
protected function restore_adding_to_course(string $backupid, string $asroleshortname): int {
global $CFG, $USER;
// Create course to restore into, and a user to do the restore.
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$restorer = $generator->create_user();
$generator->enrol_user($restorer->id, $course->id, $asroleshortname);
$this->setUser($restorer);
// Turn off file logging, otherwise it can't delete the file (Windows).
$CFG->backup_file_logger_level = backup::LOG_NONE;
// Do restore to new course with default settings.
$rc = new \restore_controller($backupid, $course->id,
backup::INTERACTIVE_NO, backup::MODE_GENERAL, $USER->id,
backup::TARGET_CURRENT_ADDING);
$precheck = $rc->execute_precheck();
$this->assertTrue($precheck);
$rc->get_plan()->get_setting('role_assignments')->set_value(true);
$rc->execute_plan();
$rc->destroy();
return $course->id;
}
public function test_restore_role_overrides_as_manager(): void {
$this->resetAfterTest();
$this->setAdminUser();
// Create a course and back it up.
$course = $this->create_course_with_role_overrides();
$backupid = $this->backup_course($course);
// When manager restores, both role overrides should be restored.
$newcourseid = $this->restore_adding_to_course($backupid, 'manager');
// Verify.
$overrides = $this->get_overrides_for_role_on_context('teacher',
context_course::instance($newcourseid));
$this->assertArrayHasKey('moodle/user:loginas', $overrides);
$this->assertEquals(CAP_ALLOW, $overrides['moodle/user:loginas']);
$this->assertArrayHasKey('moodle/site:accessallgroups', $overrides);
$this->assertEquals(CAP_ALLOW, $overrides['moodle/site:accessallgroups']);
}
public function test_restore_role_overrides_as_teacher(): void {
$this->resetAfterTest();
$this->setAdminUser();
// Create a course and back it up.
$course = $this->create_course_with_role_overrides();
$backupid = $this->backup_course($course);
// When teacher restores, only the safe override should be restored.
$newcourseid = $this->restore_adding_to_course($backupid, 'editingteacher');
// Verify.
$overrides = $this->get_overrides_for_role_on_context('teacher',
context_course::instance($newcourseid));
$this->assertArrayNotHasKey('moodle/user:loginas', $overrides);
$this->assertArrayHasKey('moodle/site:accessallgroups', $overrides);
$this->assertEquals(CAP_ALLOW, $overrides['moodle/site:accessallgroups']);
}
}
+13
View File
@@ -126,6 +126,19 @@ abstract class base_plan implements checksumable, executable {
return $result;
}
/**
* For debug only. Get a simple test display of all the settings.
*
* @return string
*/
public function debug_display_all_settings_values(): string {
$result = '';
foreach ($this->settings as $name => $setting) {
$result .= $name . ': ' . $setting->get_value() . "\n";
}
return $result;
}
/**
* Wrapper over @get_setting() that returns if the requested setting exists or no
*/
@@ -14,10 +14,8 @@ Feature: Duplicate activities
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And I log in as "admin"
And I set the following administration settings values:
| backup_import_activities | 0 |
And I log out
And the following config values are set as admin:
| backup_import_activities | 0 | backup |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I add a "Database" to section "1" and I fill the form with:
@@ -24,9 +24,9 @@ Feature: Edit activities in main menu block
@javascript
Scenario: Activities in main menu block can be made available but not visible on a course page
And I log in as "admin"
And I set the following administration settings values:
Given the following config values are set as admin:
| allowstealth | 1 |
And I log in as "admin"
And I am on site homepage
And I navigate to "Turn editing on" in current page administration
And I add the "Main menu" block
@@ -33,10 +33,8 @@ Feature: Edit activities in social activities block
@javascript
Scenario: Activities in social activities block can be made available but not visible on a course page
And I log in as "admin"
And I set the following administration settings values:
Given the following config values are set as admin:
| allowstealth | 1 |
And I log out
And I log in as "user1"
And I am on "Course 1" course homepage with editing mode on
And I add the "Recent activity" block
+1 -6
View File
@@ -2154,11 +2154,7 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
// Change our event's date to the 20th Monday of the current year.
$twentiethmonday = new DateTime(date('Y-01-01'));
$twentiethmonday->modify('+20 Monday');
$startdatetime = $this->change_event_startdate($twentiethmonday->format('Ymd\T090000'), 'US/Eastern');
$startdate = new DateTime($startdatetime->format('Y-m-d'));
$offset = $startdatetime->diff($startdate, true);
$startdatetime = $this->change_event_startdate($twentiethmonday->format('Ymd\T000000'), 'US/Eastern');
$interval = new DateInterval('P1Y');
@@ -2183,7 +2179,6 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$expecteddate->modify('January 1');
$expecteddate->add($interval);
$expecteddate->modify("+20 Monday");
$expecteddate->add($offset);
}
}
@@ -131,10 +131,8 @@ Feature: Toggle activities visibility from the course page
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And I log in as "admin"
And I set the following administration settings values:
And the following config values are set as admin:
| allowstealth | 1 |
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I add the "Recent activity" block
@@ -42,9 +42,9 @@ Feature: Activity navigation
| wiki | Wiki 1 | Test wiki description | C1 | wiki1 | 6 |
| workshop | Workshop 1 | Test workshop description | C1 | workshop1 | 6 |
| assign | Assignment 1 | Test assignment description | C2 | assign21 | 0 |
And I log in as "admin"
And I set the following administration settings values:
And the following config values are set as admin:
| allowstealth | 1 |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
# Stealth activity.
And I click on "Hide" "link" in the "Forum 1" activity
+11 -8
View File
@@ -11,16 +11,16 @@ Feature: Add activities to courses
| student2 | Student | 2 | student2@example.com |
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
| Course 1 | Course 1 | topics |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student2 | C1 | student |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
| student1 | Course 1 | student |
| student2 | Course 1 | student |
@javascript
Scenario: Add an activity to a course
Given I am on the "Course 1" Course page logged in as admin
And I am on "Course 1" course homepage with editing mode on
When I add a "Database" to section "3" and I fill the form with:
| Name | Test name |
| Description | Test database description |
@@ -38,15 +38,18 @@ Feature: Add activities to courses
@javascript
Scenario: Add an activity supplying only the name
Given I am on the "Course 1" Course page logged in as admin
And I am on "Course 1" course homepage with editing mode on
When I add a "Database" to section "3" and I fill the form with:
| Name | Test name |
Then I should see "Test name"
@javascript
Scenario: Set activity description to required then add an activity supplying only the name
Given I set the following administration settings values:
| requiremodintro | Yes |
When I am on "Course 1" course homepage
Given the following config values are set as admin:
| requiremodintro | 1 |
And I am on the "Course 1" Course page logged in as admin
And I am on "Course 1" course homepage with editing mode on
And I add a "Database" to section "3" and I fill the form with:
| Name | Test name |
Then I should see "Required"
@@ -6,9 +6,9 @@ Feature: Courses can be set up to display dates relative to the user's enrolment
@javascript
Scenario: Create a course with relative dates feature disabled
Given I log in as "admin"
And I set the following administration settings values:
Given the following config values are set as admin:
| enablecourserelativedates | 0 |
And I log in as "admin"
And I am on site homepage
And I turn editing mode on
When I press "Add a new course"
@@ -18,20 +18,19 @@ Feature: Courses can be set up to display dates relative to the user's enrolment
@javascript
Scenario: Create a course with relative dates feature enabled
Given I log in as "admin"
And I set the following administration settings values:
Given the following config values are set as admin:
| enablecourserelativedates | 1 |
And I log in as "admin"
And I am on site homepage
And I turn editing mode on
When I press "Add a new course"
And I wait until the page is ready
Then I should see "Relative dates mode"
And I should see "Relative dates mode cannot be changed once the course has been created."
Scenario: Edit courses with relative dates feature enabled
Given I log in as "admin"
And I set the following administration settings values:
Given the following config values are set as admin:
| enablecourserelativedates | 1 |
And I log in as "admin"
And I create a course with:
| Course full name | Course 1 |
| Course short name | C1 |
+3 -3
View File
@@ -13,11 +13,11 @@ Feature: Users can request and approve courses
Scenario: Simple course request workflow
Given the following "system role assigns" exist:
| user | course | role |
| user | course | role |
| user2 | Acceptance test site | manager |
Given I log in as "admin"
And I set the following administration settings values:
And the following config values are set as admin:
| lockrequestcategory | 1 |
Given I log in as "admin"
And I set the following system permissions of "Authenticated user" role:
| capability | permission |
| moodle/course:request | Allow |
+13 -10
View File
@@ -47,23 +47,23 @@
* @param int $fontsize the font size
* @return string the latex document
*/
function construct_latex_document( $formula, $fontsize=12 ) {
global $CFG;
$formula = filter_tex_sanitize_formula($formula);
function construct_latex_document($formula, $fontsize = 12) {
// $fontsize don't affects to formula's size. $density can change size
$doc = "\\documentclass[{$fontsize}pt]{article}\n";
$doc = "\\documentclass[{$fontsize}pt]{article}\n";
$doc .= get_config('filter_tex', 'latexpreamble');
$doc .= "\\pagestyle{empty}\n";
$doc .= "\\begin{document}\n";
//dlnsk $doc .= "$ {$formula} $\n";
if (preg_match("/^[[:space:]]*\\\\begin\\{(gather|align|alignat|multline).?\\}/i",$formula)) {
if (preg_match("/^[[:space:]]*\\\\begin\\{(gather|align|alignat|multline).?\\}/i", $formula)) {
$doc .= "$formula\n";
} else {
$doc .= "$ {$formula} $\n";
}
$doc .= "\\end{document}\n";
// Sanitize the whole document (rather than just the formula) to make sure no one can bypass sanitization
// by using \newcommand in preamble to give an alias to a blocked command.
$doc = filter_tex_sanitize_formula($doc);
return $doc;
}
@@ -114,11 +114,14 @@
$convertformat = 'png';
}
$filename = str_replace(".{$convertformat}", '', $filename);
$tex = "{$this->temp_dir}/$filename.tex";
$tex = "$filename.tex"; // Absolute paths won't work with openin_any = p setting.
$dvi = "{$this->temp_dir}/$filename.dvi";
$ps = "{$this->temp_dir}/$filename.ps";
$img = "{$this->temp_dir}/$filename.{$convertformat}";
// Change directory to temp dir so that we can work with relative paths.
chdir($this->temp_dir);
// turn the latex doc into a .tex file in the temp area
$fh = fopen( $tex, 'w' );
fputs( $fh, $doc );
@@ -126,7 +129,7 @@
// run latex on document
$command = "$pathlatex --interaction=nonstopmode --halt-on-error $tex";
chdir( $this->temp_dir );
if ($this->execute($command, $log)) { // It allways False on Windows
// return false;
}
+30 -2
View File
@@ -61,7 +61,7 @@ function filter_tex_get_executable($debug=false) {
function filter_tex_sanitize_formula($texexp) {
/// Check $texexp against blacklist (whitelisting could be more complete but also harder to maintain)
$tex_blacklist = array(
$denylist = [
'include','command','loop','repeat','open','toks','output',
'input','catcode','name','^^',
'\def','\edef','\gdef','\xdef',
@@ -71,9 +71,37 @@ function filter_tex_sanitize_formula($texexp) {
'\afterassignment','\expandafter','\noexpand','\special',
'\let', '\futurelet','\else','\fi','\chardef','\makeatletter','\afterground',
'\noexpand','\line','\mathcode','\item','\section','\mbox','\declarerobustcommand'
];
$allowlist = ['inputenc'];
// Prepare the denylist for regular expression.
$denylist = array_map(function($value){
return '/' . preg_quote($value, '/') . '/i';
}, $denylist);
// Prepare the allowlist for regular expression.
$allowlist = array_map(function($value){
return '/\bforbiddenkeyword_(' . preg_quote($value, '/') . ')\b/i';
}, $allowlist);
// First, mangle all denied words.
$texexp = preg_replace_callback($denylist,
function($matches) {
return 'forbiddenkeyword_' . $matches[0];
},
$texexp
);
return str_ireplace($tex_blacklist, 'forbiddenkeyword', $texexp);
// Then, change back the allowed words.
$texexp = preg_replace_callback($allowlist,
function($matches) {
return $matches[1];
},
$texexp
);
return $texexp;
}
function filter_tex_get_cmd($pathname, $texexp) {
+65
View File
@@ -0,0 +1,65 @@
<?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/>.
/**
* Tex filter library functions tests
*
* @package filter_tex
* @category test
* @copyright 2021 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
declare(strict_types=1);
namespace filter_tex;
use advanced_testcase;
global $CFG;
require_once($CFG->dirroot . '/filter/tex/lib.php');
/**
* Tex filter library functions tests
*
* @copyright 2021 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class lib_test extends advanced_testcase {
/**
* Data provider for test_filter_tex_sanitize_formula.
*
* @return array
*/
public function filter_tex_sanitize_formula_provider() : array {
return [
['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}'],
];
}
/**
* Tests for filter_tex_sanitize_formula() function.
*
* @dataProvider filter_tex_sanitize_formula_provider
* @param $formula The formula to test
* @param $expected The sanitized version of the formula we expect to get
*/
public function test_filter_tex_sanitize_formula(string $formula, string $expected) {
$this->assertEquals($expected, filter_tex_sanitize_formula($formula));
}
}
+4 -4
View File
@@ -238,12 +238,15 @@
$output .= "<p>base filename for expression is '$md5'</p>\n";
// temporary paths
$tex = "$latex->temp_dir/$md5.tex";
$tex = "$md5.tex"; // Absolute paths won't work with openin_any = p setting.
$dvi = "$latex->temp_dir/$md5.dvi";
$ps = "$latex->temp_dir/$md5.ps";
$convertformat = get_config('filter_tex', 'convertformat');
$img = "$latex->temp_dir/$md5.{$convertformat}";
// Change directory to temp dir so that we can work with relative paths.
chdir($latex->temp_dir);
// put the expression as a file into the temp area
$expression = html_entity_decode($expression);
$output .= "<p>Processing TeX expression:</p><pre>$expression</pre>\n";
@@ -252,9 +255,6 @@
fputs($fh, $doc);
fclose($fh);
// cd to temp dir
chdir($latex->temp_dir);
// step 1: latex command
$pathlatex = escapeshellarg($pathlatex);
$cmd = "$pathlatex --interaction=nonstopmode --halt-on-error $tex";
+4 -8
View File
@@ -85,20 +85,16 @@ $string['pathsunsecuredataroot'] = 'La ubicación de dataroot no es segura';
$string['pathswrongadmindir'] = 'El directorio admin no existe';
$string['phpextension'] = 'Extensión PHP {$a}';
$string['phpversion'] = 'Versión PHP';
$string['phpversionhelp'] = '<p>Moodle requiere al menos una versión de PHP 4.3.0 o 5.1.0 ((5.0.x tiene una serie de problemas conocidos).</p>
<p>En este momento está ejecutando la versión {$a}</p>
<p>¡Debe actualizar PHP o trasladarse a otro servidor con una versión más reciente de PHP!<br />
(En caso de 5.0.x podría también revertir a la versión 4.4.x)</p>';
$string['phpversionhelp'] = '<p>Moodle requiere una versión de PHP que sea al menos la 5.6.5 o 7.1 (7.0.x tiene algunas limitaciones del motor).</p>
<p>En este momento está ejecutando la versión {$a}.</p>
<p>Debe actualizar PHP o trasladarse a otro servidor con una versión más reciente de PHP.</p>';
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['welcomep20'] = 'Si está viendo esta página es porque ha podido ejecutar el paquete <strong>{$a->packname} {$a->packversion}</strong> satisfactoriamente en su ordenador. ¡Enhorabuena!';
$string['welcomep30'] = 'Esta versión de <strong>{$a->installername}</strong> incluye las
aplicaciones necesarias para que <strong>Moodle</strong> funcione en su ordenador,
principalmente:';
$string['welcomep40'] = 'El paquete también incluye <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
$string['welcomep50'] = 'El uso de todas las aplicaciones del paquete está gobernado por sus respectivas
licencias. El programa <strong>{$a->installername}</strong> es
<a href="http://www.opensource.org/docs/definition_plain.html">código abierto</a> y se distribuye
bajo licencia <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
$string['welcomep50'] = 'El uso de todas las aplicaciones del paquete está supeditado a sus respectivas licencias. El programa <strong>{$a->installername}</strong> es <a href="http://www.opensource.org/docs/definition_plain.html">de código abierto</a> y se distribuye bajo licencia <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
$string['welcomep60'] = 'Las siguientes páginas le guiarán a través de algunos sencillos pasos para configurar y ajustar <strong>Moodle</strong> en su ordenador. Puede utilizar los valores por defecto sugeridos o, de forma opcional, modificarlos para que se ajusten a sus necesidades.';
$string['welcomep70'] = 'Pulse en el botón "Siguiente" para continuar con la configuración de <strong>Moodle</strong>.';
$string['wwwroot'] = 'Dirección Web';
+1
View File
@@ -39,3 +39,4 @@ $string['cliunknowoption'] = 'Tunnistamaton valinta: {$a} Ole hyvä ja käytä -
$string['cliyesnoprompt'] = 'syötä k (kyllä) tai e (ei)';
$string['environmentrequireinstall'] = 'pitää olla asennettuna ja käytössä';
$string['environmentrequireversion'] = 'versio {$a->needed} vaaditaan ja käytössä on versio {$a->current}';
$string['upgradekeyset'] = 'Päivitysavain (jätä tyhjäksi, jos et halua asettaa sitä)';
+1 -1
View File
@@ -70,7 +70,7 @@ $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['welcomep20'] = 'Anda melihat halaman ini karena Anda telah berhasil memasang dan meluncurkan paket <strong> {$a->packname} {$a->packversion}</strong> di komputer Anda. Selamat!';
$string['welcomep30'] = 'Rilis <strong> {$a->installername}</strong> ini mencakup aplikasi untuk menciptakan lingkungan tempat <strong> Moodle </strong> yang akan digunakan, yaitu:';
$string['welcomep40'] = 'Paket juga termasuk <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
$string['welcomep50'] = 'Penggunaan semua aplikasi dalam paket ini diatur oleh lisensi masing-masing. Paket <strong>{$a->installername}</strong> lengkap adalah <a href="http://www.opensource.org/docs/definition_plain.html"> sumber terbuka </a> dan didistribusikan di bawah lisensi <a href="http://www.gnu.org/copyleft/gpl.html"> GPL </a>.';
$string['welcomep50'] = 'Penggunaan semua aplikasi dalam paket ini diatur oleh lisensi masing-masing. Paket lengkap <strong>{$a->installername}</strong> adalah <a href="https://www.opensource.org/docs/definition_plain.html"> open source </a> dan didistribusikan di bawah lisensi <a href="https://www.gnu.org/copyleft/gpl.html">GPL</a>.';
$string['welcomep60'] = 'Halaman berikut akan menuntun Anda melalui beberapa langkah yang mudah diikuti untuk mengonfigurasi dan menyiapkan <strong> Moodle </strong> di komputer Anda. Anda dapat menerima pengaturan bawaan atau, secara opsional, mengubahnya sesuai dengan kebutuhan Anda.';
$string['welcomep70'] = 'Klik tombol "Selanjutnya" di bawah untuk melanjutkan instalasi <strong> Moodle </strong>.';
$string['wwwroot'] = 'Alamat web';
+2 -2
View File
@@ -37,6 +37,6 @@ $string['clitypevalue'] = 'introduza valor';
$string['clitypevaluedefault'] = 'introduza valor, pressione a tecla \'Enter\' para usar o valor predefinido ({$a})';
$string['cliunknowoption'] = 'Opções desconhecidas: {$a}. Por favor, use a opção --help';
$string['cliyesnoprompt'] = 'digite s (para sim) ou n (para não)';
$string['environmentrequireinstall'] = 'deve estar instalada e ativa';
$string['environmentrequireversion'] = 'é requerida a versão {$a->needed} e está a correr a versão {$a->current}';
$string['environmentrequireinstall'] = 'tem de estar instalada e ativa';
$string['environmentrequireversion'] = 'é requerida a versão {$a->needed} e está a usar a versão {$a->current}';
$string['upgradekeyset'] = 'Chave de atualização (deixe em branco caso não pretenda definir)';
+1 -1
View File
@@ -54,7 +54,7 @@ $string['pathserrcreatedataroot'] = 'O programa de instalação não conseguiu c
$string['pathshead'] = 'Confirmar caminhos';
$string['pathsrodataroot'] = 'A pasta de dados não tem permissões de escrita.';
$string['pathsroparentdataroot'] = 'A pasta ascendente <b>{$a->parent}</b> não tem permissões de escrita. O programa de instalação não conseguiu criar a pasta <b>{$a->dataroot}</b>.';
$string['pathssubadmindir'] = 'Alguns servidores Web utilizam a pasta <strong>admin</strong> em URLs especiais de acesso a funcionalidades especiais, como é o caso de painéis de controlo. Algumas situações podem criar conflitos com a localização normal das páginas de administração do Moodle. Estes problemas podem ser resolvidos renomeando a pasta <strong>admin</strong> na instalação do Moodle e indicando aqui o novo nome a utilizar. Por exemplo:<br /><br /><b>moodleadmin</b><br /><br />Esta ação resolverá os problemas de acesso das hiperligações para as funcionalidades de administração do Moodle.';
$string['pathssubadmindir'] = 'Alguns servidores Web utilizam a pasta <strong>admin</strong> em URLs especiais de acesso a funcionalidades especiais, como é o caso de painéis de controlo. Algumas situações podem criar conflitos com a localização normal das páginas de administração do Moodle. Estes problemas podem ser resolvidos renomeando a pasta <strong>admin</strong> na instalação do Moodle e indicando aqui o novo nome a utilizar. Exemplo:<br /><br /><b>moodleadmin</b><br /><br />Esta ação resolverá os problemas de acesso das hiperligações para as funcionalidades de administração do Moodle.';
$string['pathssubdataroot'] = '<p>Pasta onde o Moodle irá armazenar todo o conteúdo de ficheiros enviados pelos utilizadores.</p>
<p>Esta pasta deve ser legível e gravável pelo utilizador do servidor web (geralmente \'www-data\', \'nobody\', ou \'apache\').</p>
<p>Não deve ser acessível diretamente através da web.</p>
+1
View File
@@ -33,6 +33,7 @@ $string['admindirname'] = 'Skrbniška mapa';
$string['availablelangs'] = 'Jezikovni paketi na voljo';
$string['chooselanguagehead'] = 'Izberite jezik';
$string['chooselanguagesub'] = 'Izberite jezik za namestitev. Pozneje boste lahko izbrali tudi jezike strani in uporabniške jezike.';
$string['clialreadyconfigured'] = 'Konfiguracijska datoteka config.php že obstaja. Uporabite admin/cli/install_database.php, če želite namestiti Moodle na to spletno mesto.';
$string['clialreadyinstalled'] = 'Datoteka config.php že obstaja, prosimo uporabite admin/cli/install_database.php, če želite posodobiti vašo stran.';
$string['cliinstallheader'] = 'Moodle {$a} namestitveni program z ukazno vrstico';
$string['databasehost'] = 'Gostitelj podatkovne baze';
+1 -1
View File
@@ -34,7 +34,7 @@ $string['availablelangs'] = 'Tillgängliga språkpaket';
$string['chooselanguagehead'] = 'Välj ett språk';
$string['chooselanguagesub'] = 'Vänligen välj ett språk för installationen. Du kommer att ha möjlighet att välja språk för webbplatsen och användarna på en senare skärm.';
$string['clialreadyconfigured'] = 'Filen <em>config.php</em> finns redan. Använd <code>admin/cli/install_database.php</code> för att installera Moodle på denna server.';
$string['clialreadyinstalled'] = 'Filen config.php finns redan. Vänligen använd admin/cli/upgrade.php om Du vill uppgradera Din webbplats.';
$string['clialreadyinstalled'] = 'Filen <code>config.php</code> finns redan. Vänligen använd <code>admin/cli/upgrade.php</code> om du vill uppgradera Moodle på den här webbplatsen.';
$string['cliinstallheader'] = 'Kommandoradsbaserat installationsprogram för Moodle {$a}';
$string['databasehost'] = 'Databasserver';
$string['databasename'] = 'Namn på databas';
+1
View File
@@ -659,6 +659,7 @@ $string['checkboxyes'] = 'Yes';
$string['choosefiletoedit'] = 'Choose file to edit';
$string['h5pgetcontenttypestask'] = 'Download available H5P content types from h5p.org';
$string['iconvrequired'] = 'Installing ICONV extension is required.';
$string['igbinary322buggyversion'] = 'The php-igbinary extension installed on the site can lead to problems when running with PHP 7.2. You are recommended to either upgrade to php-igbinary 3.2.5 or later, or alternatively to upgrade to PHP 7.3 or later.';
$string['ignore'] = 'Ignore';
$string['includemoduleuserdata'] = 'Include module user data';
$string['incompatibleblocks'] = 'Incompatible blocks';
+3 -3
View File
@@ -549,7 +549,7 @@ abstract class behat_generator_base {
$cmtable = new \core\dml\table('course_modules', 'cm', 'cm');
$cmfrom = $cmtable->get_from_sql();
$acttable = new \core\dml\table($activity, 'act', 'act');
$acttable = new \core\dml\table($activity, 'a', 'a');
$actselect = $acttable->get_field_select();
$actfrom = $acttable->get_from_sql();
@@ -558,8 +558,8 @@ abstract class behat_generator_base {
FROM {$cmfrom}
INNER JOIN {$coursefrom} ON c.id = cm.course
INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
INNER JOIN {$actfrom} ON cm.instance = act.id
WHERE cm.idnumber = :idnumber OR act.name = :name
INNER JOIN {$actfrom} ON cm.instance = a.id
WHERE cm.idnumber = :idnumber OR a.name = :name
EOF;
$result = $DB->get_record_sql($sql, [
+3 -3
View File
@@ -1546,7 +1546,7 @@ EOF;
$cmtable = new \core\dml\table('course_modules', 'cm', 'cm');
$cmfrom = $cmtable->get_from_sql();
$acttable = new \core\dml\table($activity, 'act', 'act');
$acttable = new \core\dml\table($activity, 'a', 'a');
$actselect = $acttable->get_field_select();
$actfrom = $acttable->get_from_sql();
@@ -1555,8 +1555,8 @@ EOF;
FROM {$cmfrom}
INNER JOIN {$coursefrom} ON c.id = cm.course
INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
INNER JOIN {$actfrom} ON cm.instance = act.id
WHERE cm.idnumber = :idnumber OR act.name = :name
INNER JOIN {$actfrom} ON cm.instance = a.id
WHERE cm.idnumber = :idnumber OR a.name = :name
EOF;
$result = $DB->get_record_sql($sql, [
+3
View File
@@ -655,6 +655,7 @@ $capabilities = array(
)
),
// The ability to override the permissions for any capability.
'moodle/role:override' => array(
'riskbitmask' => RISK_SPAM | RISK_PERSONAL | RISK_XSS,
@@ -666,6 +667,8 @@ $capabilities = array(
)
),
// The ability to override the permissions for 'safe' capabilities (those without risks).
// If a user has moodle/role:override then you should not check this capability.
'moodle/role:safeoverride' => array(
'riskbitmask' => RISK_SPAM,
+9 -2
View File
@@ -1717,7 +1717,7 @@ EOF;
}
/**
* Press a named key with an optional set of modifiers.
* Press a named or character key with an optional set of modifiers.
*
* Supported named keys are:
* - up
@@ -1735,6 +1735,8 @@ EOF;
* - enter
* - tab
*
* You can also use a single character for the key name e.g. 'Ctrl C'.
*
* Supported moderators are:
* - shift
* - ctrl
@@ -1830,7 +1832,12 @@ EOF;
$keys[] = behat_keys::SPACE;
break;
default:
throw new \coding_exception("Unknown key '$key'}");
// You can enter a single ASCII character (e.g. a letter) to directly type that key.
if (strlen($key) === 1) {
$keys[] = strtolower($key);
} else {
throw new \coding_exception("Unknown key '$key'}");
}
}
behat_base::type_keys($this->getSession(), $keys);
+53
View File
@@ -2422,6 +2422,59 @@ function check_sixtyfour_bits(environment_results $result) {
return null;
}
/**
* Check if the igbinary extension installed is buggy one
*
* There are a few php-igbinary versions that are buggy and
* return any unserialised array with wrong index. This defeats
* key() and next() operations on them.
*
* This library is used by MUC and also by memcached and redis
* when available.
*
* Let's inform if there is some problem when:
* - php 7.2 is being used (php 7.3 and up are immune).
* - the igbinary extension is installed.
* - the version of the extension is between 3.2.2 and 3.2.4.
* - the buggy behaviour is reproduced.
*
* @param environment_results $result object to update, if relevant.
* @return environment_results|null updated results or null.
*/
function check_igbinary322_version(environment_results $result) {
// No problem if using PHP version 7.3 and up.
$phpversion = normalize_version(phpversion());
if (version_compare($phpversion, '7.3', '>=')) {
return null;
}
// No problem if igbinary is not installed..
if (!function_exists('igbinary_serialize')) {
return null;
}
// No problem if using igbinary < 3.2.2 or > 3.2.4.
$igbinaryversion = normalize_version(phpversion('igbinary'));
if (version_compare($igbinaryversion, '3.2.2', '<') or version_compare($igbinaryversion, '3.2.4', '>')) {
return null;
}
// Let's verify the real behaviour to see if the bug is around.
// Note that we need this extra check because they released 3.2.5 with 3.2.4 version number, so
// over the paper, there are 3.2.4 working versions (3.2.5 ones with messed reflection version).
$data = [1, 2, 3];
$data = igbinary_unserialize(igbinary_serialize($data));
if (key($data) === 0) {
return null;
}
// Arrived here, we are using PHP 7.2 and a buggy verified igbinary version, let's inform and don't allow to continue.
$result->setInfo('igbinary version problem');
$result->setStatus(false);
return $result;
}
/**
* Assert the upgrade key is provided, if it is defined.
*
+3 -5
View File
@@ -110,10 +110,8 @@ Feature: Anonymous feedback
And I log out
Scenario: Complete fully anonymous feedback on the front page as a guest
And I log in as "admin"
And I set the following administration settings values:
Given the following config values are set as admin:
| feedback_allowfullanonymous | 1 |
And I log out
When I follow "Site feedback"
And I follow "Preview"
And I should see "Do you like our site?"
@@ -128,9 +126,9 @@ Feature: Anonymous feedback
@javascript
Scenario: Complete fully anonymous feedback and view analyze on the front page as a guest
And I log in as "admin"
And I set the following administration settings values:
Given the following config values are set as admin:
| feedback_allowfullanonymous | 1 |
And I log in as "admin"
And I set the following system permissions of "Guest" role:
| capability | permission |
| mod/feedback:viewanalysepage | Allow |
@@ -14,10 +14,10 @@ Feature: View fill the blanks attempt report
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
And I log in as "admin"
# No HTML should appear even with formatstringstriptags disabled.
And I set the following administration settings values:
And the following config values are set as admin:
# No HTML should appear even with formatstringstriptags disabled.
| formatstringstriptags | 0 |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
And I add a "H5P" to section "1"
And I set the following fields to these values:
@@ -14,10 +14,10 @@ Feature: View essay attempt report
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
And I log in as "admin"
# No HTML should appear even with formatstringstriptags disabled.
And I set the following administration settings values:
And the following config values are set as admin:
# No HTML should appear even with formatstringstriptags disabled.
| formatstringstriptags | 0 |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
And I add a "H5P" to section "1"
And I set the following fields to these values:
+13 -2
View File
@@ -413,10 +413,21 @@ class mod_quiz_external extends external_api {
require_capability('mod/quiz:viewreports', $context);
}
// Update quiz with override information.
$quiz = quiz_update_effective_access($quiz, $params['userid']);
$attempts = quiz_get_user_attempts($quiz->id, $user->id, $params['status'], $params['includepreviews']);
$attemptresponse = [];
foreach ($attempts as $attempt) {
$reviewoptions = quiz_get_review_options($quiz, $attempt, $context);
if (!has_capability('mod/quiz:viewreports', $context) &&
($reviewoptions->marks < question_display_options::MARK_AND_MAX || $attempt->state != quiz_attempt::FINISHED)) {
// Blank the mark if the teacher does not allow it.
$attempt->sumgrades = null;
}
$attemptresponse[] = $attempt;
}
$result = array();
$result['attempts'] = $attempts;
$result['attempts'] = $attemptresponse;
$result['warnings'] = $warnings;
return $result;
}
+49 -1
View File
@@ -109,15 +109,19 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase {
* @param boolean $startattempt whether to start a new attempt
* @param boolean $finishattempt whether to finish the new attempt
* @param string $behaviour the quiz preferredbehaviour, defaults to 'deferredfeedback'.
* @param boolean $includeqattachments whether to include a question that supports attachments, defaults to false.
* @param array $extraoptions extra options for Quiz.
* @return array array containing the quiz, context and the attempt
*/
private function create_quiz_with_questions($startattempt = false, $finishattempt = false, $behaviour = 'deferredfeedback') {
private function create_quiz_with_questions($startattempt = false, $finishattempt = false, $behaviour = 'deferredfeedback',
$includeqattachments = false, $extraoptions = []) {
// Create a new quiz with attempts.
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$data = array('course' => $this->course->id,
'sumgrades' => 2,
'preferredbehaviour' => $behaviour);
$data = array_merge($data, $extraoptions);
$quiz = $quizgenerator->create_instance($data);
$context = context_module::instance($quiz->cmid);
@@ -130,6 +134,12 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase {
$question = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
quiz_add_quiz_question($question->id, $quiz);
if ($includeqattachments) {
$question = $questiongenerator->create_question('essay', null, array('category' => $cat->id, 'attachments' => 1,
'attachmentsrequired' => 1));
quiz_add_quiz_question($question->id, $quiz);
}
$quizobj = quiz::create($quiz->id, $this->student->id);
// Set grade to pass.
@@ -387,6 +397,8 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase {
$this->assertEquals($quiz->id, $result['attempts'][0]['quiz']);
$this->assertEquals($this->student->id, $result['attempts'][0]['userid']);
$this->assertEquals(1, $result['attempts'][0]['attempt']);
$this->assertArrayHasKey('sumgrades', $result['attempts'][0]);
$this->assertEquals(1.0, $result['attempts'][0]['sumgrades']);
// Test filters. Only finished.
$result = mod_quiz_external::get_user_attempts($quiz->id, 0, 'finished', false);
@@ -452,6 +464,42 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase {
}
}
/**
* Test get_user_attempts with marks hidden
*/
public function test_get_user_attempts_with_marks_hidden() {
// Create quiz with one attempt finished and hide the mark.
list($quiz, $context, $quizobj, $attempt, $attemptobj) = $this->create_quiz_with_questions(
true, true, 'deferredfeedback', false,
['marksduring' => 0, 'marksimmediately' => 0, 'marksopen' => 0, 'marksclosed' => 0]);
// Student cannot see the grades.
$this->setUser($this->student);
$result = mod_quiz_external::get_user_attempts($quiz->id);
$result = external_api::clean_returnvalue(mod_quiz_external::get_user_attempts_returns(), $result);
$this->assertCount(1, $result['attempts']);
$this->assertEquals($attempt->id, $result['attempts'][0]['id']);
$this->assertEquals($quiz->id, $result['attempts'][0]['quiz']);
$this->assertEquals($this->student->id, $result['attempts'][0]['userid']);
$this->assertEquals(1, $result['attempts'][0]['attempt']);
$this->assertArrayHasKey('sumgrades', $result['attempts'][0]);
$this->assertEquals(null, $result['attempts'][0]['sumgrades']);
// Test manager can see user grades.
$this->setUser($this->teacher);
$result = mod_quiz_external::get_user_attempts($quiz->id, $this->student->id);
$result = external_api::clean_returnvalue(mod_quiz_external::get_user_attempts_returns(), $result);
$this->assertCount(1, $result['attempts']);
$this->assertEquals($attempt->id, $result['attempts'][0]['id']);
$this->assertEquals($quiz->id, $result['attempts'][0]['quiz']);
$this->assertEquals($this->student->id, $result['attempts'][0]['userid']);
$this->assertEquals(1, $result['attempts'][0]['attempt']);
$this->assertArrayHasKey('sumgrades', $result['attempts'][0]);
$this->assertEquals(1.0, $result['attempts'][0]['sumgrades']);
}
/**
* Test get_user_best_grade
*/
+801 -549
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -19,9 +19,9 @@
"eslint-plugin-babel": "5.3.0",
"eslint-plugin-promise": "4.2.1",
"fb-watchman": "2.0.1",
"gherkin-lint": "4.0.1",
"gherkin-lint": "^4.2.2",
"glob": "7.1.6",
"grunt": "1.1.0",
"grunt": "^1.4.1",
"grunt-babel": "8.0.0",
"grunt-contrib-uglify": "4.0.1",
"grunt-contrib-watch": "1.1.0",
@@ -35,7 +35,7 @@
"stylelint": "13.3.3",
"stylelint-checkstyle-formatter": "0.1.2",
"stylelint-csstree-validator": "1.8.0",
"xmldom": "0.3.0",
"xmldom": "^0.6.0",
"xpath": "0.0.27"
},
"engines": {
@@ -7,23 +7,24 @@ Feature: Use the particiaption report to message groups of students
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
| Course 1 | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
| student3 | Student | 3 | student3@example.com |
| username | firstname | lastname |
| teacher1 | Teacher | 1 |
| student1 | Student | 1 |
| student2 | Student | 2 |
| student3 | Student | 3 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
And the following "activity" exists:
| course | C1 |
| activity | book |
| name | Test book name |
| idnumber | Test book name |
| description | Test book |
| idnumber | book1 |
And I am on the "Test book name" "book activity" page logged in as student1
+2 -7
View File
@@ -6,13 +6,8 @@ $drawer-padding-x: 20px !default;
$drawer-padding-y: 20px !default;
$drawer-offscreen-gutter: 20px !default;
:target::before {
content: " ";
display: block;
height: ($fixed-header-y + 10px); /* fixed header height*/
margin-top: -($fixed-header-y + 10px); /* negative fixed header height */
width: 1px;
pointer-events: none;
:target {
scroll-margin-top: $fixed-header-y + 10px;
}
.pagelayout-embedded :target {
+2 -9
View File
@@ -14031,15 +14031,8 @@ span.editinstructions {
white-space: pre-wrap; }
/* Anchor link offset fix. This makes hash links scroll 60px down to account for the fixed header. */
:target::before {
content: " ";
display: block;
height: 60px;
/* fixed header height*/
margin-top: -60px;
/* negative fixed header height */
width: 1px;
pointer-events: none; }
:target {
scroll-margin-top: 60px; }
.pagelayout-embedded :target {
padding-top: initial;
+2 -9
View File
@@ -14247,15 +14247,8 @@ span.editinstructions {
white-space: pre-wrap; }
/* Anchor link offset fix. This makes hash links scroll 60px down to account for the fixed header. */
:target::before {
content: " ";
display: block;
height: 60px;
/* fixed header height*/
margin-top: -60px;
/* negative fixed header height */
width: 1px;
pointer-events: none; }
:target {
scroll-margin-top: 60px; }
.pagelayout-embedded :target {
padding-top: initial;
+22 -4
View File
@@ -101,15 +101,33 @@ if ($formaction == 'bulkchange.php') {
$identityfieldsselect .= ', u.' . $field . ' ';
}
if (!empty($userids)) {
list($insql, $inparams) = $DB->get_in_or_equal($userids);
// Ensure users are enrolled in this course context, further limiting them by selected userids.
[$enrolledsql, $enrolledparams] = get_enrolled_sql($context);
[$useridsql, $useridparams] = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED, 'userid');
$params = array_merge($enrolledparams, $useridparams);
// If user can only view their own groups then they can only export users from those groups too.
$groupmode = groups_get_course_groupmode($course);
if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $context)) {
$groups = groups_get_all_groups($course->id, $USER->id, 0, 'g.id');
$groupids = array_column($groups, 'id');
[$groupmembersql, $groupmemberparams] = groups_get_members_ids_sql($groupids, $context);
$params = array_merge($params, $groupmemberparams);
$groupmemberjoin = "JOIN ({$groupmembersql}) jg ON jg.id = u.id";
} else {
$groupmemberjoin = '';
}
$sql = "SELECT u.firstname, u.lastname" . $identityfieldsselect . "
FROM {user} u
WHERE u.id $insql";
JOIN ({$enrolledsql}) je ON je.id = u.id
{$groupmemberjoin}
WHERE u.id {$useridsql}";
$rs = $DB->get_recordset_sql($sql, $inparams);
$rs = $DB->get_recordset_sql($sql, $params);
// Provide callback to pre-process all records ensuring user identity fields are escaped if HTML supported.
\core\dataformat::download_data(
@@ -51,11 +51,9 @@ Feature: The student can navigate to their grades page and user grade report.
| Test assignment three | 0.00 %( Empty ) | - | 0150 | - | 0.00 % |
Scenario: Change Grades settings to go to a custom url.
When I log in as "admin"
And I set the following administration settings values:
| grade_mygrades_report | External URL |
| gradereport_mygradeurl | /badges/mybadges.php |
And I log out
Given the following config values are set as admin:
| grade_mygrades_report | external |
| gradereport_mygradeurl | /badges/mybadges.php |
And I log in as "student1"
And I follow "Student 1"
And I follow "Grades" in the user menu
+2 -2
View File
@@ -29,9 +29,9 @@
defined('MOODLE_INTERNAL') || die();
$version = 2020061509.00; // 20200615 = branching date YYYYMMDD - do not modify!
$version = 2020061510.00; // 20200615 = branching date YYYYMMDD - do not modify!
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '3.9.9 (Build: 20210729)'; // Human-friendly version name
$release = '3.9.10 (Build: 20210913)'; // Human-friendly version name
$branch = '39'; // This version's branch.
$maturity = MATURITY_STABLE; // This version's maturity level.