Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a900d6ed9 | |||
| 385721f105 | |||
| 83c5af5001 | |||
| 1b995b811d | |||
| 52ad957d74 | |||
| edb68975d1 | |||
| 9d84286479 | |||
| 7b8be76dd9 | |||
| c2bcdedbd6 | |||
| ca40241461 | |||
| 5e7ec29c65 | |||
| 193e6b0fad | |||
| b7a8375e65 | |||
| 10e93d074b | |||
| 0e6246db29 | |||
| 58efa0fa10 | |||
| afc3bfc296 | |||
| 9af8958b03 | |||
| 896da8f473 | |||
| 90fa1113f2 | |||
| aaf985001e | |||
| 9b81be597c | |||
| 998f6ce060 | |||
| 881ad82c44 | |||
| 5c163fff89 | |||
| 1ac64c87f9 | |||
| ce35013ebf | |||
| 8de6b2d6f4 | |||
| 81fc25e7fa | |||
| 5efe1cbf3c | |||
| 5deff67cea | |||
| 14cb950ff3 | |||
| 374028b418 | |||
| f0133eaae1 | |||
| 18998a6051 | |||
| 00b94dec34 | |||
| 71269d9c8f | |||
| 61c44c40d8 | |||
| 4629c45815 |
@@ -82,6 +82,8 @@ class behat_admin extends behat_base {
|
||||
|
||||
$this->execute('behat_forms::i_set_the_field_with_xpath_to', [$fieldxpath, $value]);
|
||||
$this->execute("behat_general::i_click_on", [get_string('savechanges'), 'button']);
|
||||
// Wait for the page to be redirected.
|
||||
$this->execute("behat_general::i_wait_to_be_redirected");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ $action = optional_param('action', '', PARAM_ALPHA);
|
||||
// Handle any single operation actions.
|
||||
if ($action == 'requestanalysis') {
|
||||
if ($courseid != 0) {
|
||||
require_sesskey();
|
||||
scheduler::request_course_analysis($courseid);
|
||||
if ($courseid == SITEID) {
|
||||
redirect(accessibility::get_plugin_url());
|
||||
|
||||
@@ -218,12 +218,11 @@ class helper {
|
||||
* @return moodle_url The URL.
|
||||
*/
|
||||
public static function get_duplicate_tour_link($tourid) {
|
||||
$link = new \moodle_url('/admin/tool/usertours/configure.php', [
|
||||
return new \moodle_url('/admin/tool/usertours/configure.php', [
|
||||
'action' => manager::ACTION_DUPLICATETOUR,
|
||||
'id' => $tourid,
|
||||
'sesskey' => sesskey(),
|
||||
]);
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -512,8 +512,9 @@ class manager {
|
||||
* @param int $tourid The ID of the tour to duplicate.
|
||||
*/
|
||||
protected function duplicate_tour($tourid) {
|
||||
$tour = helper::get_tour($tourid);
|
||||
require_sesskey();
|
||||
|
||||
$tour = helper::get_tour($tourid);
|
||||
$export = $tour->to_record();
|
||||
// Remove the id.
|
||||
unset($export->id);
|
||||
|
||||
@@ -168,8 +168,7 @@ abstract class restore_qtype_plugin extends restore_plugin {
|
||||
$this->questionanswercacheid = $newquestionid;
|
||||
// Cache all cleaned answers for a simple text match.
|
||||
foreach ($answers as $answer) {
|
||||
// MDL-30018: Clean in the same way as {@link xml_writer::xml_safe_utf8()}.
|
||||
$clean = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is','', $answer->answer); // Clean CTRL chars.
|
||||
$clean = core_text::trim_ctrl_chars($answer->answer); // Clean CTRL chars.
|
||||
$clean = preg_replace("/\r\n|\r/", "\n", $clean); // Normalize line ending.
|
||||
$this->questionanswercache[$clean] = $answer->id;
|
||||
}
|
||||
|
||||
@@ -5154,8 +5154,7 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
$potentialhints = $DB->get_records('question_hints',
|
||||
array('questionid' => $newquestionid), '', 'id, hint');
|
||||
foreach ($potentialhints as $potentialhint) {
|
||||
// Clean in the same way than {@link xml_writer::xml_safe_utf8()}.
|
||||
$cleanhint = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is','', $potentialhint->hint); // Clean CTRL chars.
|
||||
$cleanhint = core_text::trim_ctrl_chars($potentialhint->hint); // Clean CTRL chars.
|
||||
$cleanhint = preg_replace("/\r\n|\r/", "\n", $cleanhint); // Normalize line ending.
|
||||
if ($cleanhint === $data->hint) {
|
||||
$newitemid = $data->id;
|
||||
|
||||
@@ -253,14 +253,14 @@ class xml_writer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform some UTF-8 cleaning, stripping the control chars (\x0-\x1f)
|
||||
* but tabs (\x9), newlines (\xa) and returns (\xd). The delete control
|
||||
* Perform some UTF-8 cleaning, stripping the control chars (\x00-\x1f)
|
||||
* but tabs (\x09), newlines (\xa) and returns (\xd). The delete control
|
||||
* char (\x7f) is also included. All them are forbiden in XML 1.0 specs.
|
||||
* The expression below seems to be UTF-8 safe too because it simply
|
||||
* ignores the rest of characters. Also normalize linefeeds and return chars.
|
||||
*/
|
||||
protected function xml_safe_utf8($content) {
|
||||
$content = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is', '', $content ?? ''); // clean CTRL chars.
|
||||
$content = core_text::trim_ctrl_chars($content ?? '');
|
||||
$content = preg_replace("/\r\n|\r/", "\n", $content); // Normalize line&return=>line
|
||||
return fix_utf8($content);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Script to let a user edit the properties of a particular RSS feed.
|
||||
* Script to let a user view the output of a particular RSS feed.
|
||||
*
|
||||
* @package block_rss_client
|
||||
* @copyright 2009 Tim Hunt
|
||||
@@ -26,9 +26,6 @@ require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir .'/simplepie/moodle_simplepie.php');
|
||||
|
||||
require_login();
|
||||
if (isguestuser()) {
|
||||
throw new \moodle_exception('guestsarenotallowed');
|
||||
}
|
||||
|
||||
$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);
|
||||
$courseid = optional_param('courseid', 0, PARAM_INT);
|
||||
@@ -46,6 +43,11 @@ if ($courseid) {
|
||||
$PAGE->set_context($context);
|
||||
}
|
||||
|
||||
$managesharedfeeds = has_capability('block/rss_client:manageanyfeeds', $context);
|
||||
if (!$managesharedfeeds) {
|
||||
require_capability('block/rss_client:manageownfeeds', $context);
|
||||
}
|
||||
|
||||
$urlparams = array('rssid' => $rssid);
|
||||
if ($courseid) {
|
||||
$urlparams['courseid'] = $courseid;
|
||||
@@ -56,10 +58,18 @@ if ($returnurl) {
|
||||
$PAGE->set_url('/blocks/rss_client/viewfeed.php', $urlparams);
|
||||
$PAGE->set_pagelayout('popup');
|
||||
|
||||
$rssrecord = $DB->get_record('block_rss_client', array('id' => $rssid), '*', MUST_EXIST);
|
||||
if ($managesharedfeeds) {
|
||||
$select = 'id = :id AND (userid = :userid OR shared = 1)';
|
||||
} else {
|
||||
$select = 'id = :id AND userid = :userid';
|
||||
}
|
||||
|
||||
$rssrecord = $DB->get_record_select('block_rss_client', $select, [
|
||||
'id' => $rssid,
|
||||
'userid' => $USER->id,
|
||||
], '*', MUST_EXIST);
|
||||
|
||||
$rss = new moodle_simplepie($rssrecord->url);
|
||||
|
||||
if ($rss->error()) {
|
||||
debugging($rss->error());
|
||||
throw new \moodle_exception('errorfetchingrssfeed');
|
||||
|
||||
@@ -55,11 +55,11 @@ class cohorts extends system_report {
|
||||
"{$entitymainalias}.component");
|
||||
|
||||
// Check if report needs to show a specific category.
|
||||
$contextid = $this->get_parameter('contextid', 0, PARAM_INT);
|
||||
$showall = $this->get_parameter('showall', true, PARAM_BOOL);
|
||||
if (!$showall) {
|
||||
if (!$this->get_context() instanceof context_system || !$this->get_parameter('showall', false, PARAM_BOOL)) {
|
||||
$paramcontextid = database::generate_param_name();
|
||||
$this->add_base_condition_sql("{$entitymainalias}.contextid = :$paramcontextid", [$paramcontextid => $contextid]);
|
||||
$this->add_base_condition_sql("{$entitymainalias}.contextid = :{$paramcontextid}", [
|
||||
$paramcontextid => $this->get_context()->id,
|
||||
]);
|
||||
}
|
||||
|
||||
// Now we can call our helper methods to add the content we want to include in the report.
|
||||
@@ -77,14 +77,7 @@ class cohorts extends system_report {
|
||||
* @return bool
|
||||
*/
|
||||
protected function can_view(): bool {
|
||||
$contextid = $this->get_parameter('contextid', 0, PARAM_INT);
|
||||
if ($contextid) {
|
||||
$context = context::instance_by_id($contextid, MUST_EXIST);
|
||||
} else {
|
||||
$context = context_system::instance();
|
||||
}
|
||||
|
||||
return has_any_capability(['moodle/cohort:manage', 'moodle/cohort:view'], $context);
|
||||
return has_any_capability(['moodle/cohort:manage', 'moodle/cohort:view'], $this->get_context());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,10 +91,8 @@ class cohorts extends system_report {
|
||||
public function add_columns(cohort $cohortentity): void {
|
||||
|
||||
$entitymainalias = $cohortentity->get_table_alias('cohort');
|
||||
$showall = $this->get_parameter('showall', false, PARAM_BOOL);
|
||||
|
||||
// Category column. An extra callback is appended in order to extend the current column formatting.
|
||||
if ($showall) {
|
||||
if ($this->get_context() instanceof context_system && $this->get_parameter('showall', false, PARAM_BOOL)) {
|
||||
$this->add_column_from_entity('cohort:context')
|
||||
->add_callback(static function(string $value, stdClass $cohort): string {
|
||||
$context = context::instance_by_id($cohort->contextid);
|
||||
@@ -195,10 +186,11 @@ class cohorts extends system_report {
|
||||
*/
|
||||
protected function add_actions(): void {
|
||||
|
||||
$contextid = $this->get_parameter('contextid', 0, PARAM_INT);
|
||||
$showall = $this->get_parameter('showall', true, PARAM_BOOL);
|
||||
$returnurl = (new moodle_url('/cohort/index.php',
|
||||
['id' => ':id', 'contextid' => $contextid, 'showall' => $showall]))->out(false);
|
||||
$returnurl = (new moodle_url('/cohort/index.php', [
|
||||
'id' => ':id',
|
||||
'contextid' => $this->get_context()->id,
|
||||
'showall' => $this->get_parameter('showall', false, PARAM_BOOL),
|
||||
]))->out(false);
|
||||
|
||||
// Hide action. It will be only shown if the property 'visible' is true and user has 'moodle/cohort:manage' capabillity.
|
||||
$this->add_action((new action(
|
||||
|
||||
+1
-2
@@ -104,8 +104,7 @@ if ($editcontrols = cohort_edit_controls($context, $baseurl)) {
|
||||
echo $OUTPUT->render($editcontrols);
|
||||
}
|
||||
|
||||
$reportparams = ['contextid' => $context->id, 'showall' => $showall];
|
||||
$report = system_report_factory::create(cohorts::class, $context, '', '', 0, $reportparams);
|
||||
$report = system_report_factory::create(cohorts::class, $context, '', '', 0, ['showall' => $showall]);
|
||||
|
||||
// Check if it needs to search by name.
|
||||
if (!empty($searchquery)) {
|
||||
|
||||
+12
-6
@@ -4177,22 +4177,28 @@ class core_course_external extends external_api {
|
||||
* @param int $groupid Group id from which the users will be obtained
|
||||
* @param bool $onlyactive Whether to return only the active enrolled users or all enrolled users in the course.
|
||||
* @return array List of users
|
||||
* @throws invalid_parameter_exception
|
||||
*/
|
||||
public static function get_enrolled_users_by_cmid(int $cmid, int $groupid = 0, bool $onlyactive = false) {
|
||||
global $PAGE;
|
||||
global $PAGE;
|
||||
|
||||
$warnings = [];
|
||||
|
||||
self::validate_parameters(self::get_enrolled_users_by_cmid_parameters(), [
|
||||
'cmid' => $cmid,
|
||||
'groupid' => $groupid,
|
||||
'onlyactive' => $onlyactive,
|
||||
[
|
||||
'cmid' => $cmid,
|
||||
'groupid' => $groupid,
|
||||
'onlyactive' => $onlyactive,
|
||||
] = self::validate_parameters(self::get_enrolled_users_by_cmid_parameters(), [
|
||||
'cmid' => $cmid,
|
||||
'groupid' => $groupid,
|
||||
'onlyactive' => $onlyactive,
|
||||
]);
|
||||
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($cmid);
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
self::validate_context($coursecontext);
|
||||
|
||||
course_require_view_participants($coursecontext);
|
||||
|
||||
$enrolledusers = get_enrolled_users($coursecontext, '', $groupid, 'u.*', null, 0, 0, $onlyactive);
|
||||
|
||||
$users = array_map(function ($user) use ($PAGE) {
|
||||
|
||||
@@ -242,6 +242,9 @@ class stateactions {
|
||||
|
||||
foreach ($ids as $sectionid) {
|
||||
$section = $modinfo->get_section_info_by_id($sectionid, MUST_EXIST);
|
||||
if (!course_can_delete_section($course, $section)) {
|
||||
continue;
|
||||
}
|
||||
// Send all activity deletions.
|
||||
if (!empty($modinfo->sections[$section->section])) {
|
||||
foreach ($modinfo->sections[$section->section] as $modnumber) {
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
<?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/>.
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace core_courseformat\external;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use core_courseformat\stateactions;
|
||||
use core_courseformat\stateupdates;
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
|
||||
|
||||
/**
|
||||
* Tests for the delete section test class.
|
||||
*
|
||||
* @package core_courseformat
|
||||
* @copyright 2025 Laurent David <laurent.david@moodle.com>
|
||||
* @category test
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \core_courseformat\stateactions
|
||||
*/
|
||||
final class delete_section_test extends \externallib_advanced_testcase {
|
||||
|
||||
/**
|
||||
* Setup to ensure that fixtures are loaded.
|
||||
*/
|
||||
public static function setupBeforeClass(): void { // phpcs:ignore
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittestdelete.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the webservice can execute the section_delete action.
|
||||
*
|
||||
* @covers ::section_delete
|
||||
* @dataProvider section_delete_provider
|
||||
* @param int $sectionum
|
||||
* @param string $format
|
||||
* @param array $formatoptions
|
||||
* @param int $expectedsectionum
|
||||
*
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
public function test_delete_section(int $sectionum, string $format, array $formatoptions, int $expectedsectionum): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course =
|
||||
$this->getDataGenerator()->create_course(array_merge(
|
||||
['numsections' => $sectionum, 'format' => $format],
|
||||
$formatoptions,
|
||||
));
|
||||
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
|
||||
// Execute the method.
|
||||
$courseformat = course_get_format($course->id);
|
||||
$updates = new stateupdates($courseformat);
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
$sections = $modinfo->get_section_info_all();
|
||||
$sectionsid = array_map(function ($section) {
|
||||
return $section->id;
|
||||
}, $sections);
|
||||
$actions = new stateactions();
|
||||
$this->setUser($teacher);
|
||||
$actions->section_delete(
|
||||
$updates,
|
||||
$course,
|
||||
$sectionsid
|
||||
);
|
||||
// Check result.
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
$sections = $modinfo->get_section_info_all();
|
||||
$this->assertCount($expectedsectionum, $sections);
|
||||
if ($format == 'theunittestdelete') {
|
||||
$this->assertDebuggingCalled();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for the test_delete_section method.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function section_delete_provider(): array {
|
||||
return [
|
||||
'format topic' => [
|
||||
'sectionum' => 1,
|
||||
'format' => 'topics',
|
||||
'formatoptions' => [],
|
||||
'expectedsectionum' => 1,
|
||||
],
|
||||
'format theunittestdelete' => [
|
||||
'sectionum' => 1,
|
||||
'format' => 'theunittestdelete',
|
||||
'formatoptions' => [],
|
||||
'expectedsectionum' => 2,
|
||||
],
|
||||
'format theunittestdelete can delete' => [
|
||||
'sectionum' => 1,
|
||||
'format' => 'theunittestdelete',
|
||||
'formatoptions' => ['can_delete_sections' => true],
|
||||
'expectedsectionum' => 1,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?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();
|
||||
require_once(__DIR__ . '/format_theunittest.php');
|
||||
|
||||
/**
|
||||
* Fixture for fake course format testing course format API.
|
||||
*
|
||||
* @package core_courseformat
|
||||
* @copyright 2025 Laurent David <laurent.david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class format_theunittestdelete extends format_theunittest {
|
||||
|
||||
/**
|
||||
* Definitions of the additional options that format uses
|
||||
*
|
||||
* @param bool $foreditform
|
||||
* @return array of options
|
||||
*/
|
||||
public function course_format_options($foreditform = false) {
|
||||
static $courseformatoptions = false;
|
||||
if ($courseformatoptions === false) {
|
||||
$courseformatoptions = parent::course_format_options(true);
|
||||
$courseformatoptionsadditional = [
|
||||
'can_delete_sections' => [
|
||||
'default' => false,
|
||||
'type' => PARAM_BOOL,
|
||||
],
|
||||
];
|
||||
$courseformatoptions = array_merge_recursive($courseformatoptions, $courseformatoptionsadditional);
|
||||
}
|
||||
return $courseformatoptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this format allows to delete sections
|
||||
*
|
||||
* Here for test purpose we just can delete one section every two sections
|
||||
*
|
||||
* Do not call this function directly, instead use course_can_delete_section()
|
||||
*
|
||||
* @param int|stdClass|section_info $section
|
||||
* @return bool
|
||||
*/
|
||||
public function can_delete_section($section) {
|
||||
return $this->get_format_options()['can_delete_sections'] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this course format uses sections
|
||||
*/
|
||||
public function uses_sections() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3742,6 +3742,12 @@ final class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
$this->assertEquals(2, count($users['users']));
|
||||
$this->assertEquals($expectedusers, $users);
|
||||
|
||||
// Prohibit the capability for viewing course participants.
|
||||
$this->unassignUserCapability('moodle/course:viewparticipants', null, null, $course1->id);
|
||||
$this->expectException(required_capability_exception::class);
|
||||
$this->expectExceptionMessage('Sorry, but you do not currently have permissions to do that (View participants)');
|
||||
core_course_external::get_enrolled_users_by_cmid($forum1->cmid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+10
-1
@@ -84,11 +84,20 @@ function filter_tex_sanitize_formula(string $texexp): string {
|
||||
'\afterassignment', '\expandafter', '\noexpand', '\special',
|
||||
'\let', '\futurelet', '\else', '\fi', '\chardef', '\makeatletter', '\afterground',
|
||||
'\noexpand', '\line', '\mathcode', '\item', '\section', '\mbox', '\declarerobustcommand',
|
||||
'\ExplSyntaxOn', '\pdffiledump',
|
||||
'\ExplSyntaxOn', '\pdffiledump', '\mathtex',
|
||||
];
|
||||
|
||||
$allowlist = ['inputenc'];
|
||||
|
||||
// Add encoded backslash (\) versions of backslashed items to deny list.
|
||||
$encodedslashdenylist = array_map(function($value) {
|
||||
$encoded = str_replace('\\', '\', $value);
|
||||
// Return an encoded slash version if a slash is found, otherwise null so we can filter it off.
|
||||
return $encoded != $value ? $encoded : null;
|
||||
}, $denylist);
|
||||
$encodedslashdenylist = array_filter($encodedslashdenylist);
|
||||
$denylist = array_merge($denylist, $encodedslashdenylist);
|
||||
|
||||
// Prepare the denylist for regular expression.
|
||||
$denylist = array_map(function($value){
|
||||
return '/' . preg_quote($value, '/') . '/i';
|
||||
|
||||
@@ -71,7 +71,7 @@ $string['pathserrcreatedataroot'] = 'Instalatzaileak ezin du datu-direktorioa ({
|
||||
$string['pathshead'] = 'Egiaztatu bideak';
|
||||
$string['pathsrodataroot'] = 'Dataroot direktorioa ez da idazteko modukoa.';
|
||||
$string['pathsroparentdataroot'] = 'Goragoko direktorioa ({$a->parent}) ez da idazteko modukoa. Instalatzaileak ezin du datu-direktorioa ({$a->dataroot}) sortu.';
|
||||
$string['pathssubadmindir'] = 'Web ostalari gutxi batzuk /admin URL berezi gisa erabiltzen dute kontrol-panel edo antzekora sarbidea emateko. Zoritxarrez, honek Moodleren kudeatze-orrien lehenetsitako kokapenarekin gatazka sortzen du. Hau konpondu dezakezu zure instalazioko admin direktorioa berrizendatuz, eta izen berria hemen sartuta. Adibidez <em>moodleadmin</em>. Honek Moodleko admin estekak konponduko du.';
|
||||
$string['pathssubadmindir'] = 'Web ostalari gutxi batzuk /admin URL berezi gisa erabiltzen dute kontrol-panel edo antzekora sarbidea emateko. Zoritxarrez, honek Moodleko kudeatze-orrien lehenetsitako kokapenarekin gatazka sortzen du. Hau konpondu dezakezu zure instalazioko admin direktorioa berrizendatuz, eta izen berria hemen sartuta. Adibidez <em>moodleadmin</em>. Honek Moodleko admin estekak konponduko du.';
|
||||
$string['pathssubdataroot'] = '<p>Moodlek erabiltzaileek igotako fitxategien edukiak bilduko dituen direktorio bat.</p>
|
||||
<p>Direktorio honetan web-zerbitzariaren erabiltzaileak irakurtzeko eta idazteko baimena izan beharko ditu (normalean \'www-data\', \'nobody\', edo \'apache\').</p>
|
||||
<p>Ez litzateke web bidez eskuragarri egon beharko.</p>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'Hizkuntza';
|
||||
$string['moodlelogo'] = 'Moodleren logoa';
|
||||
$string['moodlelogo'] = 'Moodleko logoa';
|
||||
$string['next'] = 'Hurrengoa';
|
||||
$string['previous'] = 'Aurrekoa';
|
||||
$string['reload'] = 'Berriz kargatu';
|
||||
|
||||
@@ -84,10 +84,10 @@ $string['phpversionhelp'] = '<p>Moodleには少なくとも5.6.5または7.1のP
|
||||
<p>現在、あなたはバージョン {$a} を動作させています。</p>
|
||||
<p>PHPをアップグレードするか新しいバージョンのPHPがインストールされているホストに移動する必要があります。</p>';
|
||||
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
|
||||
$string['welcomep20'] = 'インストールが正常に完了して、あなたのコンピュータで <strong>{$a->packname} {$a->packversion}</strong> パッケージが起動されたため、このページが表示されています。おめでとうございます!';
|
||||
$string['welcomep30'] = 'このリリース <strong>{$a->installername}</strong> には<strong>Moodle</strong>で環境を作成するアプリケーションが含まれています。すなわち:';
|
||||
$string['welcomep40'] = 'パッケージには <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong> も含まれています。';
|
||||
$string['welcomep50'] = 'このパッケージ内のすべてのアプリケーションの使用は個別のライセンスによって規定されています。全体の<strong>{$a->installername}</strong>パッケージは<a href="https://www.opensource.org/docs/definition_plain.html">オープンソース</a>であり、<a href="https://www.gnu.org/copyleft/gpl.html">GPL</a>ライセンスの下で配布されています。';
|
||||
$string['welcomep20'] = 'インストール正常完了後、あなたのコンピュータで<strong>{$a->packname} {$a->packversion}</strong>パッケージが起動されたため、このページが表示されています。おめでとうございます!';
|
||||
$string['welcomep30'] = 'このリリース<strong>{$a->installername}</strong>には<strong>Moodle</strong>で環境を作成するアプリケーションが含まれています。すなわち:';
|
||||
$string['welcomep40'] = 'パッケージには<strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>も含まれています。';
|
||||
$string['welcomep50'] = 'このパッケージ内すべてのアプリケーションの使用は個別のライセンスにより規定されています。全体の<strong>{$a->installername}</strong>パッケージは<a href="https://www.opensource.org/docs/definition_plain.html">オープンソース</a>であり、<a href="https://www.gnu.org/copyleft/gpl.html">GPL</a>ライセンスの下で配布されています。';
|
||||
$string['welcomep60'] = '次からのページはあなたのコンピュータに<strong>Moodle</strong>を簡単に設定およびセットアップする手順にしたがって進みます。あなたはデフォルトの設定を使用することも、必要に応じて任意で設定を変更することもできます。';
|
||||
$string['welcomep70'] = '<strong>Moodle</strong>のセットアップを続けるには「次へ」ボタンをクリックしてください。';
|
||||
$string['wwwroot'] = 'ウェブアドレス';
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'Fiteny';
|
||||
$string['moodlelogo'] = 'Sarim-pamantarana ny Moodle';
|
||||
$string['next'] = 'Manaraka';
|
||||
$string['previous'] = 'Teo aloha';
|
||||
$string['reload'] = 'Avereno';
|
||||
@@ -114,6 +114,7 @@ $string['america/chicago'] = 'America/Chicago';
|
||||
$string['america/chihuahua'] = 'America/Chihuahua';
|
||||
$string['america/ciudad_juarez'] = 'America/Ciudad_Juarez';
|
||||
$string['america/costa_rica'] = 'America/Costa_Rica';
|
||||
$string['america/coyhaique'] = 'America/Coyhaique';
|
||||
$string['america/creston'] = 'America/Creston';
|
||||
$string['america/cuiaba'] = 'America/Cuiaba';
|
||||
$string['america/curacao'] = 'America/Curacao';
|
||||
|
||||
@@ -756,6 +756,7 @@ class core_date {
|
||||
if ($intltz === null) {
|
||||
// Where intl doesn't know about a recent timezone, map it to an equivalent existing zone.
|
||||
$intltzname = strtr($tz->getName(), [
|
||||
'America/Coyhaique' => 'America/Santiago',
|
||||
'America/Ciudad_Juarez' => 'America/Denver',
|
||||
'America/Nuuk' => 'America/Godthab',
|
||||
'Europe/Kyiv' => 'Europe/Kiev',
|
||||
|
||||
@@ -676,4 +676,16 @@ class core_text {
|
||||
|
||||
return mb_convert_case($text, MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims control characters out of a string.
|
||||
* Example: (\x00-\x1f) and (\x7f)
|
||||
*
|
||||
* @param string $text Input string
|
||||
* @return string Cleaned string value
|
||||
*/
|
||||
public static function trim_ctrl_chars(string $text): string {
|
||||
// Remove control characters text.
|
||||
return preg_replace('/[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]/i', '', $text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,11 @@ Feature: Add media to Atto
|
||||
And the field "Enter name" matches value "moodle-logo.webm"
|
||||
And I wait until the page is ready
|
||||
And I click on "Insert media" "button"
|
||||
When I click on "Save changes" "button"
|
||||
Then "//a[. = 'moodle-logo.webm']" "xpath_element" should exist
|
||||
And I click on "Show more buttons" "button"
|
||||
When I click on "HTML" "button"
|
||||
Then I should see "moodle-logo.webm\">moodle-logo.webm</a>"
|
||||
And I click on "Save changes" "button"
|
||||
And ".video-js" "css_element" should exist
|
||||
|
||||
@javascript @atto_media_video
|
||||
Scenario: Insert some media as a plain video
|
||||
|
||||
+3
-3
@@ -1105,10 +1105,10 @@ function clean_param($param, $type) {
|
||||
} else if (preg_match('/^' . preg_quote($CFG->wwwroot . '/', '/') . '/i', $param)) {
|
||||
// Absolute, and matches our wwwroot.
|
||||
} else {
|
||||
|
||||
// Relative - let's make sure there are no tricks.
|
||||
if (validateUrlSyntax('/' . $param, 's-u-P-a-p-f+q?r?') && !preg_match('/javascript:/i', $param)) {
|
||||
// Looks ok.
|
||||
if (validateUrlSyntax('/' . $param, 's-u-P-a-p-f+q?r?') &&
|
||||
!preg_match('/javascript(?:.*\/{2,})?:/i', rawurldecode($param))) {
|
||||
// Valid relative local URL.
|
||||
} else {
|
||||
$param = '';
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 4.1.18 ===
|
||||
* A new method, `core_text::trim_ctrl_chars()`, has been introduced to clean control characters from text.
|
||||
This ensures cleaner input handling and prevents issues caused by invisible or non-printable characters
|
||||
|
||||
=== 4.1.12 ===
|
||||
|
||||
* Added the ability for unit tests to autoload classes in the `\[component]\tests\` namespace from the `[path/to/component]/tests/classes` directory.
|
||||
|
||||
@@ -308,8 +308,17 @@ class media_videojs_plugin extends core_media_player_native {
|
||||
|
||||
// Ogv.JS Tech.
|
||||
$this->ogvtech = false;
|
||||
if (in_array($ext, $this->ogvsupportedextensions) &&
|
||||
(core_useragent::is_safari() || core_useragent::is_ios())) {
|
||||
/* The following browsers do not support OGV natively:
|
||||
- Chrome (since version 120)
|
||||
- Edge (since version 122)
|
||||
- Safari
|
||||
- Safari on iOS
|
||||
- Firefox (since version 130)
|
||||
- Opera (since version 106)
|
||||
Refer: https://caniuse.com/ogv.
|
||||
We need to enable Ogv.JS Tech plugin for all browsers that do not support OGV natively.
|
||||
*/
|
||||
if (in_array($ext, $this->ogvsupportedextensions)) {
|
||||
$this->ogvtech = true;
|
||||
$result[] = $url;
|
||||
continue;
|
||||
|
||||
+30
-2
@@ -3388,7 +3388,7 @@ class core_message_external extends external_api {
|
||||
bool $includecontactrequests = false,
|
||||
bool $includeprivacyinfo = false
|
||||
) {
|
||||
global $CFG, $USER;
|
||||
global $CFG, $USER, $DB;
|
||||
|
||||
// All the business logic checks that really shouldn't be in here.
|
||||
if (empty($CFG->messaging)) {
|
||||
@@ -3408,9 +3408,37 @@ class core_message_external extends external_api {
|
||||
throw new moodle_exception('You do not have permission to perform this action.');
|
||||
}
|
||||
|
||||
// Return early if no userids are provided.
|
||||
if (empty($params['userids'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Filter the user IDs, removing the IDs of the users that the current user cannot view.
|
||||
require_once($CFG->dirroot . '/user/lib.php');
|
||||
$userfieldsapi = \core_user\fields::for_userpic()->including('username', 'deleted');
|
||||
$userfields = $userfieldsapi->get_sql('', false, '', '', false)->selects;
|
||||
$users = $DB->get_records_list('user', 'id', $userids, '', $userfields, 0, 100);
|
||||
$filteredids = array_filter($params['userids'], function($userid) use ($users, $params) {
|
||||
$targetuser = $users[$userid];
|
||||
// Check if the user has the contact already.
|
||||
$iscontact = \core_message\api::is_contact($params['referenceuserid'], $userid);
|
||||
if ($iscontact) {
|
||||
// User is a contact, so we can return the info for this user.
|
||||
return true;
|
||||
} else {
|
||||
// User is not a contact, so we need to check if the user is allowed to see the profile or not.
|
||||
return user_can_view_profile($targetuser);
|
||||
}
|
||||
});
|
||||
|
||||
// Return early if no user IDs are left after filtering.
|
||||
if (empty($filteredids)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return \core_message\helper::get_member_info(
|
||||
$params['referenceuserid'],
|
||||
$params['userids'],
|
||||
$filteredids,
|
||||
$params['includecontactrequests'],
|
||||
$params['includeprivacyinfo']
|
||||
);
|
||||
|
||||
@@ -745,7 +745,6 @@ class template {
|
||||
$editurl = new moodle_url('/mod/data/edit.php', $this->baseurl->params());
|
||||
$editurl->params([
|
||||
'rid' => $entry->id,
|
||||
'sesskey' => sesskey(),
|
||||
'backto' => urlencode($backurl->out(false))
|
||||
]);
|
||||
|
||||
@@ -758,7 +757,6 @@ class template {
|
||||
// Delete entry.
|
||||
$deleteurl = new moodle_url($this->baseurl, [
|
||||
'delete' => $entry->id,
|
||||
'sesskey' => sesskey(),
|
||||
'mode' => 'single',
|
||||
]);
|
||||
|
||||
|
||||
@@ -80,11 +80,6 @@ if ($manager->can_manage_templates()) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($rid) {
|
||||
// When editing an existing record, we require the session key.
|
||||
require_sesskey();
|
||||
}
|
||||
|
||||
// Get Group information for permission testing and record creation.
|
||||
$currentgroup = groups_get_activity_group($cm);
|
||||
$groupmode = groups_get_activity_groupmode($cm);
|
||||
|
||||
@@ -393,7 +393,7 @@ final class template_test extends \advanced_testcase {
|
||||
],
|
||||
'Teacher actionsmenu tag with default options' => [
|
||||
'templatecontent' => 'Some ##actionsmenu## tag',
|
||||
'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* .*delete.*{entryid}.*sesskey.*Delete.* tag|',
|
||||
'expected' => '|Some .*edit.*{entryid}.*Edit.* .*delete.*{entryid}.*Delete.* tag|',
|
||||
'rolename' => 'editingteacher',
|
||||
],
|
||||
'Teacher actionsmenu tag with default options (check Show more is not there)' => [
|
||||
@@ -689,7 +689,7 @@ final class template_test extends \advanced_testcase {
|
||||
],
|
||||
'Student actionsmenu tag with default options' => [
|
||||
'templatecontent' => 'Some ##actionsmenu## tag',
|
||||
'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* .*delete.*{entryid}.*sesskey.*Delete.* tag|',
|
||||
'expected' => '|Some .*edit.*{entryid}.*Edit.* .*delete.*{entryid}.*Delete.* tag|',
|
||||
'rolename' => 'student',
|
||||
],
|
||||
'Student actionsmenu tag with default options (check Show more is not there)' => [
|
||||
|
||||
+10
-5
@@ -243,7 +243,7 @@ if (!empty(trim($search))) {
|
||||
$PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $titleparts));
|
||||
$PAGE->set_heading($course->fullname);
|
||||
$PAGE->force_settings_menu(true);
|
||||
if ($delete && confirm_sesskey() && (data_user_can_manage_entry($delete, $data, $context))) {
|
||||
if ($delete && data_user_can_manage_entry($delete, $data, $context)) {
|
||||
$PAGE->activityheader->disable();
|
||||
}
|
||||
|
||||
@@ -284,8 +284,10 @@ if ($data->intro and empty($page) and empty($record) and $mode != 'single') {
|
||||
|
||||
/// Delete any requested records
|
||||
|
||||
if ($delete && confirm_sesskey() && (data_user_can_manage_entry($delete, $data, $context))) {
|
||||
if ($delete && data_user_can_manage_entry($delete, $data, $context)) {
|
||||
if ($confirm) {
|
||||
require_sesskey();
|
||||
|
||||
if (data_delete_record($delete, $data, $course->id, $cm->id)) {
|
||||
echo $OUTPUT->notification(get_string('recorddeleted','data'), 'notifysuccess');
|
||||
}
|
||||
@@ -320,8 +322,10 @@ if ($serialdelete) {
|
||||
$multidelete = json_decode($serialdelete);
|
||||
}
|
||||
|
||||
if ($multidelete && confirm_sesskey() && $canmanageentries) {
|
||||
if ($confirm = optional_param('confirm', 0, PARAM_INT)) {
|
||||
if ($multidelete && $canmanageentries) {
|
||||
if ($confirm) {
|
||||
require_sesskey();
|
||||
|
||||
foreach ($multidelete as $value) {
|
||||
data_delete_record($value, $data, $course->id, $cm->id);
|
||||
}
|
||||
@@ -369,7 +373,8 @@ if ($showactivity) {
|
||||
// Approve or disapprove any requested records
|
||||
$approvecap = has_capability('mod/data:approve', $context);
|
||||
|
||||
if (($approve || $disapprove) && confirm_sesskey() && $approvecap) {
|
||||
if (($approve || $disapprove) && $approvecap) {
|
||||
require_sesskey();
|
||||
$newapproved = $approve ? true : false;
|
||||
$recordid = $newapproved ? $approve : $disapprove;
|
||||
if ($approverecord = $DB->get_record('data_records', array('id' => $recordid))) { // Need to check this is valid
|
||||
|
||||
@@ -157,13 +157,10 @@ class restore_qtype_match_plugin extends restore_qtype_plugin {
|
||||
$this->questionsubcacheid = $newquestionid;
|
||||
// Cache all cleaned answers and questiontext.
|
||||
foreach ($potentialsubs as $potentialsub) {
|
||||
// Clean in the same way than {@link xml_writer::xml_safe_utf8()}.
|
||||
$cleanquestion = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is',
|
||||
'', $potentialsub->questiontext); // Clean CTRL chars.
|
||||
$cleanquestion = core_text::trim_ctrl_chars($potentialsub->questiontext); // Clean CTRL chars.
|
||||
$cleanquestion = preg_replace("/\r\n|\r/", "\n", $cleanquestion); // Normalize line ending.
|
||||
|
||||
$cleananswer = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is',
|
||||
'', $potentialsub->answertext); // Clean CTRL chars.
|
||||
$cleananswer = core_text::trim_ctrl_chars($potentialsub->answertext); // Clean CTRL chars.
|
||||
$cleananswer = preg_replace("/\r\n|\r/", "\n", $cleananswer); // Normalize line ending.
|
||||
|
||||
$this->questionsubcache[$cleanquestion][$cleananswer] = $potentialsub->id;
|
||||
|
||||
@@ -111,7 +111,7 @@ class repository_dropbox extends repository {
|
||||
*/
|
||||
public function get_reference_details($reference, $filestatus = 0) {
|
||||
global $USER;
|
||||
$ref = unserialize($reference);
|
||||
$ref = unserialize_object($reference);
|
||||
$detailsprefix = $this->get_name();
|
||||
if (isset($ref->userid) && $ref->userid != $USER->id && isset($ref->username)) {
|
||||
$detailsprefix .= ' ('.$ref->username.')';
|
||||
@@ -343,8 +343,8 @@ class repository_dropbox extends repository {
|
||||
* @return string New serialized reference
|
||||
*/
|
||||
protected function fix_old_style_reference($packed) {
|
||||
$ref = unserialize($packed);
|
||||
$ref = $this->dropbox->get_file_share_info($ref->path);
|
||||
$ref = unserialize_object($packed);
|
||||
$ref = $this->dropbox->get_file_share_info($ref->path ?? '');
|
||||
if (!$ref || empty($ref->url)) {
|
||||
// Some error occurred, do not fix reference for now.
|
||||
return $packed;
|
||||
@@ -396,10 +396,10 @@ class repository_dropbox extends repository {
|
||||
* @return object The unpacked reference
|
||||
*/
|
||||
protected function unpack_reference($packed) {
|
||||
$reference = unserialize($packed);
|
||||
$reference = unserialize_object($packed);
|
||||
if (empty($reference->url)) {
|
||||
// The reference is missing some information. Attempt to update it.
|
||||
return unserialize($this->fix_old_style_reference($packed));
|
||||
return unserialize_object($this->fix_old_style_reference($packed));
|
||||
}
|
||||
|
||||
return $reference;
|
||||
|
||||
@@ -163,6 +163,17 @@ class repository_equella extends repository {
|
||||
return ($countfailures[$sess] < 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returned unserialized object from base64 encoded file reference data
|
||||
*
|
||||
* @param string $reference
|
||||
* @return stdClass
|
||||
*/
|
||||
private function unserialize_reference(string $reference): stdClass {
|
||||
$decoded = base64_decode($reference);
|
||||
return unserialize_object($decoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a file, this function can be overridden by subclass. {@link curl}
|
||||
*
|
||||
@@ -175,7 +186,7 @@ class repository_equella extends repository {
|
||||
*/
|
||||
public function get_file($reference, $filename = '') {
|
||||
global $USER, $CFG;
|
||||
$ref = @unserialize(base64_decode($reference));
|
||||
$ref = $this->unserialize_reference($reference);
|
||||
if (!isset($ref->url) || !($url = $this->appendtoken($ref->url))) {
|
||||
// Occurs when the user isn't known..
|
||||
return null;
|
||||
@@ -201,7 +212,7 @@ class repository_equella extends repository {
|
||||
// if we had several unsuccessfull attempts to connect to server - do not try any more.
|
||||
return false;
|
||||
}
|
||||
$ref = @unserialize(base64_decode($file->get_reference()));
|
||||
$ref = $this->unserialize_reference($file->get_reference());
|
||||
if (!isset($ref->url) || !($url = $this->appendtoken($ref->url))) {
|
||||
// Occurs when the user isn't known..
|
||||
$file->set_missingsource();
|
||||
@@ -248,9 +259,8 @@ class repository_equella extends repository {
|
||||
* @param array $options additional options affecting the file serving
|
||||
*/
|
||||
public function send_file($stored_file, $lifetime=null , $filter=0, $forcedownload=false, array $options = null) {
|
||||
$reference = unserialize(base64_decode($stored_file->get_reference()));
|
||||
$url = $this->appendtoken($reference->url);
|
||||
if ($url) {
|
||||
$ref = $this->unserialize_reference($stored_file->get_reference());
|
||||
if (isset($ref->url) && $url = $this->appendtoken($ref->url)) {
|
||||
header('Location: ' . $url);
|
||||
} else {
|
||||
send_file_not_found();
|
||||
@@ -421,8 +431,8 @@ class repository_equella extends repository {
|
||||
*/
|
||||
public function get_reference_details($reference, $filestatus = 0) {
|
||||
if (!$filestatus) {
|
||||
$ref = unserialize(base64_decode($reference));
|
||||
return $this->get_name(). ': '. $ref->filename;
|
||||
$ref = $this->unserialize_reference($reference);
|
||||
return $this->get_name(). ': '. ($ref->filename ?? '');
|
||||
} else {
|
||||
return get_string('lostsource', 'repository', '');
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,4 +15,4 @@ Policy: https://moodledev.io/general/development/process/security
|
||||
|
||||
# Expiry date of this document
|
||||
# This information is considered current and up to date until 3 weeks after the next major Moodle LMS release
|
||||
Expires: 2025-05-05T01:00:00.000Z
|
||||
Expires: 2025-10-27T01:00:00.000Z
|
||||
|
||||
@@ -89,8 +89,9 @@ class behat_theme_classic_behat_admin extends behat_admin {
|
||||
}
|
||||
|
||||
$this->execute('behat_forms::i_set_the_field_with_xpath_to', [$fieldxpath, $value]);
|
||||
|
||||
$this->execute("behat_general::i_click_on", [get_string('savechanges'), 'button']);
|
||||
// Wait for the page to be redirected.
|
||||
$this->execute("behat_general::i_wait_to_be_redirected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -29,9 +29,9 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2022112817.00; // 20221128 = branching date YYYYMMDD - do not modify!
|
||||
$version = 2022112818.00; // 20221128 = branching date YYYYMMDD - do not modify!
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.1.17 (Build: 20250317)'; // Human-friendly version name
|
||||
$release = '4.1.18 (Build: 20250414)'; // Human-friendly version name
|
||||
$branch = '401'; // This version's branch.
|
||||
$maturity = MATURITY_STABLE; // This version's maturity level.
|
||||
|
||||
Reference in New Issue
Block a user