{{/text}}
diff --git a/theme/bootstrapbase/templates/core/availability_info.mustache b/theme/bootstrapbase/templates/core/availability_info.mustache
index fd81eb50ea1..ee90c956307 100644
--- a/theme/bootstrapbase/templates/core/availability_info.mustache
+++ b/theme/bootstrapbase/templates/core/availability_info.mustache
@@ -15,13 +15,47 @@
along with Moodle. If not, see .
}}
{{!
- Availability info.
+ @template core/availability_info
+
+ Renders the availability info on the course outline page.
+
+ Availability info can be displayed for activity modules or whole course
+ sections. Activity modules can be either hidden from students, or available
+ but not shown on course page (stealth), or the access can be restricted by
+ configured conditions. Sections can be hidden.
+
+ Classes required for JS:
+ * none
+
+ Data attributes required for JS:
+ * none
+
+ Context variables required for this template:
+ * classes String list of CSS classes for the wrapping element
+ * text HTML formatted text with the actual availability information
+ * ishidden Boolean flag indiciating that the item is hidden from students
+ * isstealth Boolean flag indicating that the item is in stealth mode
+ * isrestricted Boolean flag indicating that restricted access conditions apply
+ * isfullinfo Boolean flag indicating that the full list of restricted
+ access conditions is displayed (aka teacher's view).
Example context (json):
- { "classes": "", "text": "This activity is not available" }
+ {
+ "classes": "",
+ "text": "Not available unless:
{{/text}}
From 4a0a23e98fa9af3ed6f12480131a9a6b34ebbebf Mon Sep 17 00:00:00 2001
From: Damyon Wiese
Date: Fri, 9 Jun 2017 16:22:36 +0800
Subject: [PATCH 07/38] MDL-58472 videojs: Force manual initialise
If we let videojs auto-init the video/audio tags present in the page - we cannot guarantee that the
youtube library will be loaded by the time video.js is processing the tag.
Video.js uses the presence of a data-setup attibute to signal that it should auto-init this tag, so
we have to rename our config attribute to something else.
---
media/player/videojs/amd/build/loader.min.js | 2 +-
media/player/videojs/amd/src/loader.js | 2 +-
media/player/videojs/classes/plugin.php | 7 ++++++-
media/player/videojs/tests/player_test.php | 2 +-
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/media/player/videojs/amd/build/loader.min.js b/media/player/videojs/amd/build/loader.min.js
index 6c77c7f187d..d57bd6098af 100644
--- a/media/player/videojs/amd/build/loader.min.js
+++ b/media/player/videojs/amd/build/loader.min.js
@@ -1 +1 @@
-define(["jquery","core/event"],function(a,b){var c,d=function(d){c=d,e(null,a("body")),b.getLegacyEvents().done(function(b){a(document).on(b.FILTER_CONTENT_UPDATED,e)})},e=function(b,d){var e=".mediaplugin_videojs";d.find(e).addBack(e).find("audio, video").each(function(){var b=a(this).attr("id"),d=a(this).data("setup"),e=["media_videojs/video-lazy"];d.techOrder&&d.techOrder.indexOf("youtube")!==-1&&e.push("media_videojs/Youtube-lazy"),require(e,function(a){c&&(c(a),c=null),a(b,d)})})};return{setUp:d}});
\ No newline at end of file
+define(["jquery","core/event"],function(a,b){var c,d=function(d){c=d,e(null,a("body")),b.getLegacyEvents().done(function(b){a(document).on(b.FILTER_CONTENT_UPDATED,e)})},e=function(b,d){var e=".mediaplugin_videojs";d.find(e).addBack(e).find("audio, video").each(function(){var b=a(this).attr("id"),d=a(this).data("setup-lazy"),e=["media_videojs/video-lazy"];d.techOrder&&d.techOrder.indexOf("youtube")!==-1&&e.push("media_videojs/Youtube-lazy"),require(e,function(a){c&&(c(a),c=null),a(b,d)})})};return{setUp:d}});
\ No newline at end of file
diff --git a/media/player/videojs/amd/src/loader.js b/media/player/videojs/amd/src/loader.js
index 2601cf888fa..427b609eea4 100644
--- a/media/player/videojs/amd/src/loader.js
+++ b/media/player/videojs/amd/src/loader.js
@@ -62,7 +62,7 @@ define(['jquery', 'core/event'], function($, Event) {
.addBack(selector)
.find('audio, video').each(function() {
var id = $(this).attr('id'),
- config = $(this).data('setup'),
+ config = $(this).data('setup-lazy'),
modules = ['media_videojs/video-lazy'];
if (config.techOrder && config.techOrder.indexOf('youtube') !== -1) {
diff --git a/media/player/videojs/classes/plugin.php b/media/player/videojs/classes/plugin.php
index f13352fe577..3d076b046f1 100644
--- a/media/player/videojs/classes/plugin.php
+++ b/media/player/videojs/classes/plugin.php
@@ -129,8 +129,13 @@ class media_videojs_plugin extends core_media_player_native {
}
// Attributes for the video/audio tag.
+ // We use data-setup-lazy as the attribute name for the config instead of
+ // data-setup because data-setup will cause video.js to load the player as soon as the library is loaded,
+ // which is BEFORE we have a chance to load any additional libraries (youtube).
+ // The data-setup-lazy is just a tag name that video.js does not recognise so we can manually initialise
+ // it when we are sure the dependencies are loaded.
$attributes = [
- 'data-setup' => '{' . join(', ', $datasetup) . '}',
+ 'data-setup-lazy' => '{' . join(', ', $datasetup) . '}',
'id' => 'id_videojs_' . uniqid(),
'class' => get_config('media_videojs', $isaudio ? 'audiocssclass' : 'videocssclass')
];
diff --git a/media/player/videojs/tests/player_test.php b/media/player/videojs/tests/player_test.php
index 43d698c2745..7bc50ead4b5 100644
--- a/media/player/videojs/tests/player_test.php
+++ b/media/player/videojs/tests/player_test.php
@@ -230,7 +230,7 @@ class media_videojs_testcase extends advanced_testcase {
protected function youtube_plugin_engaged($t) {
$this->assertContains('mediaplugin_videojs', $t);
- $this->assertContains('data-setup="{"techOrder": ["youtube"]', $t);
+ $this->assertContains('data-setup-lazy="{"techOrder": ["youtube"]', $t);
}
/**
From fe81ef397cec413abc71a0953a0e67be02db0aba Mon Sep 17 00:00:00 2001
From: Marina Glancy
Date: Mon, 21 Mar 2016 10:20:11 +0800
Subject: [PATCH 08/38] MDL-51917 course completion: order activities in
reports
Thanks to Nick Phillips for initial patch
---
lib/completionlib.php | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/lib/completionlib.php b/lib/completionlib.php
index 80c854242db..816c7d1ca2e 100644
--- a/lib/completionlib.php
+++ b/lib/completionlib.php
@@ -423,6 +423,21 @@ class completion_info {
// Load criteria from database
$records = (array)$DB->get_records('course_completion_criteria', $params);
+ // Order records so activities are in the same order as they appear on the course view page.
+ if ($records) {
+ $activitiesorder = array_keys(get_fast_modinfo($this->course)->get_cms());
+ usort($records, function ($a, $b) use ($activitiesorder) {
+ $aidx = ($a->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) ?
+ array_search($a->moduleinstance, $activitiesorder) : false;
+ $bidx = ($b->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) ?
+ array_search($b->moduleinstance, $activitiesorder) : false;
+ if ($aidx === false || $bidx === false || $aidx == $bidx) {
+ return 0;
+ }
+ return ($aidx < $bidx) ? -1 : 1;
+ });
+ }
+
// Build array of criteria objects
$this->criteria = array();
foreach ($records as $record) {
From 02375710049d31c6cdd21f2cbca16ed1b40440b8 Mon Sep 17 00:00:00 2001
From: Juan Leyva
Date: Tue, 13 Jun 2017 11:22:33 +0100
Subject: [PATCH 09/38] MDL-58712 core_user: New function for retrieving file
area info
---
lib/filelib.php | 26 ++++++++-
lib/tests/filelib_test.php | 111 +++++++++++++++++++++++++++++++++++++
2 files changed, 134 insertions(+), 3 deletions(-)
diff --git a/lib/filelib.php b/lib/filelib.php
index b1dafb9e3a2..08123829a38 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -503,9 +503,29 @@ function file_rewrite_pluginfile_urls($text, $file, $contextid, $component, $fil
* (more information will be added as needed).
*/
function file_get_draft_area_info($draftitemid, $filepath = '/') {
- global $CFG, $USER;
+ global $USER;
$usercontext = context_user::instance($USER->id);
+ return file_get_file_area_info($usercontext->id, 'user', 'draft', $draftitemid, $filepath);
+}
+
+/**
+ * Returns information about files in an area.
+ *
+ * @param int $contextid context id
+ * @param string $component component
+ * @param string $filearea file area name
+ * @param int $itemid item id or all files if not specified
+ * @param string $filepath path to the directory from which the information have to be retrieved.
+ * @return array with the following entries:
+ * 'filecount' => number of files in the area.
+ * 'filesize' => total size of the files in the area.
+ * 'foldercount' => number of folders in the area.
+ * 'filesize_without_references' => total size of the area excluding file references.
+ * @since Moodle 3.4
+ */
+function file_get_file_area_info($contextid, $component, $filearea, $itemid = false, $filepath = '/') {
+
$fs = get_file_storage();
$results = array(
@@ -516,9 +536,9 @@ function file_get_draft_area_info($draftitemid, $filepath = '/') {
);
if ($filepath != '/') {
- $draftfiles = $fs->get_directory_files($usercontext->id, 'user', 'draft', $draftitemid, $filepath, true, true);
+ $draftfiles = $fs->get_directory_files($contextid, $component, $filearea, $itemid, $filepath, true, true);
} else {
- $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id', true);
+ $draftfiles = $fs->get_area_files($contextid, $component, $filearea, $itemid, 'id', true);
}
foreach ($draftfiles as $file) {
if ($file->is_directory()) {
diff --git a/lib/tests/filelib_test.php b/lib/tests/filelib_test.php
index ea18b514a2f..30a384918ac 100644
--- a/lib/tests/filelib_test.php
+++ b/lib/tests/filelib_test.php
@@ -1229,6 +1229,117 @@ EOF;
$file = array_shift($files);
$this->assertTrue($file->is_directory());
}
+
+ /**
+ * Test file_get_draft_area_info.
+ */
+ public function test_file_get_draft_area_info() {
+ global $USER;
+
+ $this->resetAfterTest(true);
+ $this->setAdminUser();
+ $fs = get_file_storage();
+
+ $filerecord = array(
+ 'filename' => 'one.txt',
+ );
+ $file = self::create_draft_file($filerecord);
+ $size = $file->get_filesize();
+ $draftitemid = $file->get_itemid();
+ // Add another file.
+ $filerecord = array(
+ 'itemid' => $draftitemid,
+ 'filename' => 'second.txt',
+ );
+ $file = self::create_draft_file($filerecord);
+ $size += $file->get_filesize();
+
+ // Create directory.
+ $usercontext = context_user::instance($USER->id);
+ $dir = $fs->create_directory($usercontext->id, 'user', 'draft', $draftitemid, '/testsubdir/');
+ // Add file to directory.
+ $filerecord = array(
+ 'itemid' => $draftitemid,
+ 'filename' => 'third.txt',
+ 'filepath' => '/testsubdir/',
+ );
+ $file = self::create_draft_file($filerecord);
+ $size += $file->get_filesize();
+
+ $fileinfo = file_get_draft_area_info($draftitemid);
+ $this->assertEquals(3, $fileinfo['filecount']);
+ $this->assertEquals($size, $fileinfo['filesize']);
+ $this->assertEquals(2, $fileinfo['foldercount']); // Base and directory created.
+ $this->assertEquals($size, $fileinfo['filesize_without_references']);
+
+ // Now get files from just one folder.
+ $fileinfo = file_get_draft_area_info($draftitemid, '/testsubdir/');
+ $this->assertEquals(1, $fileinfo['filecount']);
+ $this->assertEquals($file->get_filesize(), $fileinfo['filesize']);
+ $this->assertEquals(0, $fileinfo['foldercount']); // No subdirectories inside the directory.
+ $this->assertEquals($file->get_filesize(), $fileinfo['filesize_without_references']);
+
+ // Check we get the same results if we call file_get_file_area_info.
+ $fileinfo = file_get_file_area_info($usercontext->id, 'user', 'draft', $draftitemid);
+ $this->assertEquals(3, $fileinfo['filecount']);
+ $this->assertEquals($size, $fileinfo['filesize']);
+ $this->assertEquals(2, $fileinfo['foldercount']); // Base and directory created.
+ $this->assertEquals($size, $fileinfo['filesize_without_references']);
+ }
+
+ /**
+ * Test file_get_file_area_info.
+ */
+ public function test_file_get_file_area_info() {
+ global $USER;
+
+ $this->resetAfterTest(true);
+ $this->setAdminUser();
+ $fs = get_file_storage();
+
+ $filerecord = array(
+ 'filename' => 'one.txt',
+ );
+ $file = self::create_draft_file($filerecord);
+ $size = $file->get_filesize();
+ $draftitemid = $file->get_itemid();
+ // Add another file.
+ $filerecord = array(
+ 'itemid' => $draftitemid,
+ 'filename' => 'second.txt',
+ );
+ $file = self::create_draft_file($filerecord);
+ $size += $file->get_filesize();
+
+ // Create directory.
+ $usercontext = context_user::instance($USER->id);
+ $dir = $fs->create_directory($usercontext->id, 'user', 'draft', $draftitemid, '/testsubdir/');
+ // Add file to directory.
+ $filerecord = array(
+ 'itemid' => $draftitemid,
+ 'filename' => 'third.txt',
+ 'filepath' => '/testsubdir/',
+ );
+ $file = self::create_draft_file($filerecord);
+ $size += $file->get_filesize();
+
+ // Add files to user private file area.
+ $options = array('subdirs' => 1, 'maxfiles' => 3);
+ file_merge_files_from_draft_area_into_filearea($draftitemid, $file->get_contextid(), 'user', 'private', 0, $options);
+
+ $fileinfo = file_get_file_area_info($usercontext->id, 'user', 'private');
+ $this->assertEquals(3, $fileinfo['filecount']);
+ $this->assertEquals($size, $fileinfo['filesize']);
+ $this->assertEquals(2, $fileinfo['foldercount']); // Base and directory created.
+ $this->assertEquals($size, $fileinfo['filesize_without_references']);
+
+ // Now get files from just one folder.
+ $fileinfo = file_get_file_area_info($usercontext->id, 'user', 'private', 0, '/testsubdir/');
+ $this->assertEquals(1, $fileinfo['filecount']);
+ $this->assertEquals($file->get_filesize(), $fileinfo['filesize']);
+ $this->assertEquals(0, $fileinfo['foldercount']); // No subdirectories inside the directory.
+ $this->assertEquals($file->get_filesize(), $fileinfo['filesize_without_references']);
+ }
}
/**
From a4beef4e3137c3c0b35a4888df555d0ff2504abd Mon Sep 17 00:00:00 2001
From: Ankit Agarwal
Date: Wed, 14 Jun 2017 14:32:53 +0530
Subject: [PATCH 10/38] MDL-44961 logs: Keep log dates constant during restore
---
.../moodle2/restore_tool_log_logstore_subplugin.class.php | 3 +--
backup/moodle2/restore_stepslib.php | 6 ++++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/admin/tool/log/backup/moodle2/restore_tool_log_logstore_subplugin.class.php b/admin/tool/log/backup/moodle2/restore_tool_log_logstore_subplugin.class.php
index 0c00f00880a..c48c2c86c24 100644
--- a/admin/tool/log/backup/moodle2/restore_tool_log_logstore_subplugin.class.php
+++ b/admin/tool/log/backup/moodle2/restore_tool_log_logstore_subplugin.class.php
@@ -84,8 +84,7 @@ abstract class restore_tool_log_logstore_subplugin extends restore_subplugin {
}
}
- // Roll dates.
- $data->timecreated = $this->apply_date_offset($data->timecreated);
+ // There is no need to roll dates. Logs are supposed to be immutable. See MDL-44961.
// Revert other to its original php way.
$data->other = unserialize(base64_decode($data->other));
diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php
index 5d607ef780e..b539a4e60f4 100644
--- a/backup/moodle2/restore_stepslib.php
+++ b/backup/moodle2/restore_stepslib.php
@@ -3083,7 +3083,8 @@ class restore_course_logs_structure_step extends restore_structure_step {
$data = (object)($data);
- $data->time = $this->apply_date_offset($data->time);
+ // There is no need to roll dates. Logs are supposed to be immutable. See MDL-44961.
+
$data->userid = $this->get_mappingid('user', $data->userid);
$data->course = $this->get_courseid();
$data->cmid = 0;
@@ -3130,7 +3131,8 @@ class restore_activity_logs_structure_step extends restore_course_logs_structure
$data = (object)($data);
- $data->time = $this->apply_date_offset($data->time);
+ // There is no need to roll dates. Logs are supposed to be immutable. See MDL-44961.
+
$data->userid = $this->get_mappingid('user', $data->userid);
$data->course = $this->get_courseid();
$data->cmid = $this->task->get_moduleid();
From 7af8b56ab4644cb4688a6d1d3c78cfac8aeba20b Mon Sep 17 00:00:00 2001
From: Simey Lameze
Date: Wed, 7 Jun 2017 13:00:48 +0800
Subject: [PATCH 11/38] MDL-57770 tool_lp: style fixes for the competency rule
dialog
---
admin/tool/lp/templates/competency_rule_config.mustache | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/admin/tool/lp/templates/competency_rule_config.mustache b/admin/tool/lp/templates/competency_rule_config.mustache
index b0e9db8440b..167a4237e8e 100644
--- a/admin/tool/lp/templates/competency_rule_config.mustache
+++ b/admin/tool/lp/templates/competency_rule_config.mustache
@@ -81,10 +81,11 @@
{{/config}}
-
+
{{#config}}
{{/config}}
+
From f74ac6e704869d5a09613d534314a3e5918c3d8a Mon Sep 17 00:00:00 2001
From: Juan Leyva
Date: Tue, 13 Jun 2017 11:56:19 +0100
Subject: [PATCH 12/38] MDL-58712 core_user: New WS
core_user_get_private_files_info
---
lib/db/services.php | 9 +++++
lib/tests/filelib_test.php | 2 +-
user/externallib.php | 72 +++++++++++++++++++++++++++++++++
user/tests/externallib_test.php | 54 +++++++++++++++++++++++++
version.php | 2 +-
5 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/lib/db/services.php b/lib/db/services.php
index 002640edb58..7bb91d138be 100644
--- a/lib/db/services.php
+++ b/lib/db/services.php
@@ -1206,6 +1206,15 @@ $functions = array(
'type' => 'write',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
+ 'core_user_get_private_files_info' => array(
+ 'classname' => 'core_user_external',
+ 'methodname' => 'get_private_files_info',
+ 'classpath' => 'user/externallib.php',
+ 'description' => 'Returns general information about files in the user private files area.',
+ 'type' => 'read',
+ 'capabilities' => 'moodle/user:manageownfiles',
+ 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
+ ),
// Competencies functions.
'core_competency_create_competency_framework' => array(
diff --git a/lib/tests/filelib_test.php b/lib/tests/filelib_test.php
index 30a384918ac..a367aaaeaa1 100644
--- a/lib/tests/filelib_test.php
+++ b/lib/tests/filelib_test.php
@@ -1287,7 +1287,7 @@ EOF;
$this->assertEquals($size, $fileinfo['filesize_without_references']);
}
- /**
+ /**
* Test file_get_file_area_info.
*/
public function test_file_get_file_area_info() {
diff --git a/user/externallib.php b/user/externallib.php
index 5ead62ce4e9..2eea9f32a06 100644
--- a/user/externallib.php
+++ b/user/externallib.php
@@ -1860,4 +1860,76 @@ class core_user_external extends external_api {
)
);
}
+
+ /**
+ * Returns description of method parameters.
+ *
+ * @return external_function_parameters
+ * @since Moodle 3.4
+ */
+ public static function get_private_files_info_parameters() {
+ return new external_function_parameters(
+ array(
+ 'userid' => new external_value(PARAM_INT, 'Id of the user, default to current user.', VALUE_DEFAULT, 0)
+ )
+ );
+ }
+
+ /**
+ * Returns general information about files in the user private files area.
+ *
+ * @param int $userid Id of the user, default to current user.
+ * @return array of warnings and file area information
+ * @since Moodle 3.4
+ * @throws moodle_exception
+ */
+ public static function get_private_files_info($userid = 0) {
+ global $CFG, $USER;
+ require_once($CFG->libdir . '/filelib.php');
+
+ $params = self::validate_parameters(self::get_private_files_info_parameters(), array('userid' => $userid));
+ $warnings = array();
+
+ $context = context_system::instance();
+ self::validate_context($context);
+
+ if (empty($params['userid']) || $params['userid'] == $USER->id) {
+ $usercontext = context_user::instance($USER->id);
+ require_capability('moodle/user:manageownfiles', $usercontext);
+ } else {
+ $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
+ core_user::require_active_user($user);
+ // Only admins can retrieve other users information.
+ require_capability('moodle/site:config', $context);
+ $usercontext = context_user::instance($user->id);
+ }
+
+ $fileareainfo = file_get_file_area_info($usercontext->id, 'user', 'private');
+
+ $result = array();
+ $result['filecount'] = $fileareainfo['filecount'];
+ $result['foldercount'] = $fileareainfo['foldercount'];
+ $result['filesize'] = $fileareainfo['filesize'];
+ $result['filesizewithoutreferences'] = $fileareainfo['filesize_without_references'];
+ $result['warnings'] = $warnings;
+ return $result;
+ }
+
+ /**
+ * Returns description of method result value.
+ *
+ * @return external_description
+ * @since Moodle 3.4
+ */
+ public static function get_private_files_info_returns() {
+ return new external_single_structure(
+ array(
+ 'filecount' => new external_value(PARAM_INT, 'Number of files in the area.'),
+ 'foldercount' => new external_value(PARAM_INT, 'Number of folders in the area.'),
+ 'filesize' => new external_value(PARAM_INT, 'Total size of the files in the area.'),
+ 'filesizewithoutreferences' => new external_value(PARAM_INT, 'Total size of the area excluding file references'),
+ 'warnings' => new external_warnings()
+ )
+ );
+ }
}
diff --git a/user/tests/externallib_test.php b/user/tests/externallib_test.php
index be52830487f..bf9edd81fdc 100644
--- a/user/tests/externallib_test.php
+++ b/user/tests/externallib_test.php
@@ -1148,6 +1148,60 @@ class core_user_externallib_testcase extends externallib_advanced_testcase {
} catch (Exception $e) {
$this->fail('Expecting \'usernotfullysetup\' moodle_exception to be thrown.');
}
+ }
+ /**
+ * Test get_private_files_info
+ */
+ public function test_get_private_files_info() {
+
+ $this->resetAfterTest(true);
+ $user = self::getDataGenerator()->create_user();
+ $this->setUser($user);
+ $usercontext = context_user::instance($user->id);
+
+ $filerecord = array(
+ 'contextid' => $usercontext->id,
+ 'component' => 'user',
+ 'filearea' => 'private',
+ 'itemid' => 0,
+ 'filepath' => '/',
+ 'filename' => 'thefile',
+ );
+
+ $fs = get_file_storage();
+ $file = $fs->create_file_from_string($filerecord, 'abc');
+
+ // Get my private files information.
+ $result = core_user_external::get_private_files_info();
+ $result = external_api::clean_returnvalue(core_user_external::get_private_files_info_returns(), $result);
+ $this->assertEquals(1, $result['filecount']);
+ $this->assertEquals($file->get_filesize(), $result['filesize']);
+ $this->assertEquals(1, $result['foldercount']); // Base directory.
+ $this->assertEquals($file->get_filesize(), $result['filesizewithoutreferences']);
+
+ // As admin, get user information.
+ $this->setAdminUser();
+ $result = core_user_external::get_private_files_info($user->id);
+ $result = external_api::clean_returnvalue(core_user_external::get_private_files_info_returns(), $result);
+ $this->assertEquals(1, $result['filecount']);
+ $this->assertEquals($file->get_filesize(), $result['filesize']);
+ $this->assertEquals(1, $result['foldercount']); // Base directory.
+ $this->assertEquals($file->get_filesize(), $result['filesizewithoutreferences']);
+ }
+
+ /**
+ * Test get_private_files_info missing permissions.
+ */
+ public function test_get_private_files_info_missing_permissions() {
+
+ $this->resetAfterTest(true);
+ $user1 = self::getDataGenerator()->create_user();
+ $user2 = self::getDataGenerator()->create_user();
+ $this->setUser($user1);
+
+ $this->setExpectedException('required_capability_exception');
+ // Try to retrieve other user private files info.
+ core_user_external::get_private_files_info($user2->id);
}
}
diff --git a/version.php b/version.php
index e90db3493dd..597192ca5a9 100644
--- a/version.php
+++ b/version.php
@@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
-$version = 2017060800.00; // YYYYMMDD = weekly release date of this DEV branch.
+$version = 2017060800.01; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
From 30e891e08fcdf0bca4982e037bedc4672484f19f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Mudr=C3=A1k?=
Date: Thu, 15 Jun 2017 20:51:58 +0200
Subject: [PATCH 13/38] MDL-46418 repositories: Fix how enabled repositories
are populated
Repository instances are stored in the 'repository' table. Repositories
in the table are either 'Enabled and visible' or 'Enabled but hidden'.
Hidden repositories still serve their files, but are not visible in the
filepicker UI. Disabling a repository instance removes its record from
the table.
In the original implementation of the plugin manager (see b9934a17), the
method plugintype_repository::get_enabled_repositories() correctly
returned all records from the repository table. Then as a part of the
bigger refactoring in MDL-41437, the commit bde002b8 replaced the
original method with the new get_enabled_plugins() one which started to
return visible repositories only.
As a consequence, the admin tree stopped populating setting page nodes
for hidden repository instances. So attempting to visit their setting
page threw a section error. Credit goes to Ike Quigley for debugging and
tracing this down.
This patch fixes the way how the list of enabled repositories is
populated by the plugin manager so that both visible and hidden
repositories are returned again. This does not affect the filepicker
itself as it is using its own methods for obtaining the list.
---
lib/classes/plugininfo/repository.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/classes/plugininfo/repository.php b/lib/classes/plugininfo/repository.php
index 861b24d2547..689edde3c91 100644
--- a/lib/classes/plugininfo/repository.php
+++ b/lib/classes/plugininfo/repository.php
@@ -37,7 +37,7 @@ class repository extends base {
*/
public static function get_enabled_plugins() {
global $DB;
- return $DB->get_records_menu('repository', array('visible'=>1), 'type ASC', 'type, type AS val');
+ return $DB->get_records_menu('repository', null, 'type ASC', 'type, type AS val');
}
public function get_settings_section_name() {
From 509679e203815b710a24650ea9f08d5d9778e690 Mon Sep 17 00:00:00 2001
From: Jean-Roch Meurisse - University of Namur - Belgium
Date: Fri, 16 Jun 2017 09:58:41 +0800
Subject: [PATCH 14/38] MDL-59263 roles: Wrong order of parameters in calls to
pix_icon function
---
admin/roles/usersroles.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/admin/roles/usersroles.php b/admin/roles/usersroles.php
index 5e871e6198b..c455902c03e 100644
--- a/admin/roles/usersroles.php
+++ b/admin/roles/usersroles.php
@@ -193,8 +193,8 @@ function print_report_tree($contextid, $contexts, $systemcontext, $fullname, $al
$strgoto = get_string('gotoassignroles', 'core_role', $a);
$strcheck = get_string('checkuserspermissionshere', 'core_role', $a);
}
- echo ' ' . $OUTPUT->pix_icon('t/edit', 'core', $stredit) . ' ';
- echo ' ' . $OUTPUT->pix_icon('t/preview', 'core', $strcheckpermissions) . ' ';
+ echo ' ' . $OUTPUT->pix_icon('t/edit', $stredit) . ' ';
+ echo ' ' . $OUTPUT->pix_icon('t/preview', $strcheckpermissions) . ' ';
echo "
\n";
}
}
From 3b5865396ed8aa88aab311959e4109b59a115daa Mon Sep 17 00:00:00 2001
From: Jun Pataleta
Date: Wed, 17 May 2017 16:45:51 +0800
Subject: [PATCH 15/38] MDL-56979 group: Make group index page Boost-y
---
group/classes/output/index_page.php | 111 +++++++++++++++++++++
group/classes/output/renderer.php | 50 ++++++++++
group/index.php | 124 +++++++-----------------
group/templates/index.mustache | 145 ++++++++++++++++++++++++++++
4 files changed, 342 insertions(+), 88 deletions(-)
create mode 100644 group/classes/output/index_page.php
create mode 100644 group/classes/output/renderer.php
create mode 100644 group/templates/index.mustache
diff --git a/group/classes/output/index_page.php b/group/classes/output/index_page.php
new file mode 100644
index 00000000000..8430aae74b9
--- /dev/null
+++ b/group/classes/output/index_page.php
@@ -0,0 +1,111 @@
+.
+
+/**
+ * Group index page.
+ *
+ * @package core_group
+ * @copyright 2017 Jun Pataleta
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace core_group\output;
+defined('MOODLE_INTERNAL') || die();
+
+use renderable;
+use renderer_base;
+use stdClass;
+use templatable;
+
+/**
+ * Group index page class.
+ *
+ * @package core_group
+ * @copyright 2017 Jun Pataleta
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class index_page implements renderable, templatable {
+
+ /** @var int $courseid The course ID. */
+ public $courseid;
+
+ /** @var array The array of groups to be rendered. */
+ public $groups;
+
+ /** @var string The name of the currently selected group. */
+ public $selectedgroupname;
+
+ /** @var array The array of group members to be rendered, if a group is selected. */
+ public $selectedgroupmembers;
+
+ /** @var bool Whether to disable the add members/edit group buttons. */
+ public $disableaddedit;
+
+ /** @var bool Whether to disable the delete group button. */
+ public $disabledelete;
+
+ /** @var array Groups that can't be deleted by the user. */
+ public $undeletablegroups;
+
+ /**
+ * index_page constructor.
+ *
+ * @param int $courseid The course ID.
+ * @param array $groups The array of groups to be rendered.
+ * @param string $selectedgroupname The name of the currently selected group.
+ * @param array $selectedgroupmembers The array of group members to be rendered, if a group is selected.
+ * @param bool $disableaddedit Whether to disable the add members/edit group buttons.
+ * @param bool $disabledelete Whether to disable the delete group button.
+ * @param array $undeletablegroups Groups that can't be deleted by the user.
+ */
+ public function __construct($courseid, $groups, $selectedgroupname, $selectedgroupmembers, $disableaddedit, $disabledelete,
+ $undeletablegroups) {
+ $this->courseid = $courseid;
+ $this->groups = $groups;
+ $this->selectedgroupname = $selectedgroupname;
+ $this->selectedgroupmembers = $selectedgroupmembers;
+ $this->disableaddedit = $disableaddedit;
+ $this->disabledelete = $disabledelete;
+ $this->undeletablegroups = $undeletablegroups;
+ }
+
+ /**
+ * Export the data.
+ *
+ * @param renderer_base $output
+ * @return stdClass
+ */
+ public function export_for_template(renderer_base $output) {
+ global $CFG;
+
+ $data = new stdClass();
+
+ // Variables that will be passed to the JS helper.
+ $data->courseid = $this->courseid;
+ $data->wwwroot = $CFG->wwwroot;
+ // To be passed to the JS init script in the template. Encode as a JSON string.
+ $data->undeletablegroups = json_encode($this->undeletablegroups);
+
+ // Some buttons are enabled if single group selected.
+ $data->addmembersdisabled = $this->disableaddedit;
+ $data->editgroupsettingsdisabled = $this->disableaddedit;
+ $data->deletegroupdisabled = $this->disabledelete;
+ $data->groups = $this->groups;
+ $data->members = $this->selectedgroupmembers;
+ $data->selectedgroup = $this->selectedgroupname;
+
+ return $data;
+ }
+}
diff --git a/group/classes/output/renderer.php b/group/classes/output/renderer.php
new file mode 100644
index 00000000000..14443cf7891
--- /dev/null
+++ b/group/classes/output/renderer.php
@@ -0,0 +1,50 @@
+.
+
+/**
+ * Renderers.
+ *
+ * @package core_group
+ * @copyright 2017 Jun Pataleta
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_group\output;
+
+defined('MOODLE_INTERNAL') || die();
+
+use plugin_renderer_base;
+
+/**
+ * Renderer class.
+ *
+ * @package core_group
+ * @copyright 2017 Jun Pataleta
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class renderer extends plugin_renderer_base {
+
+ /**
+ * Defer to template.
+ *
+ * @param index_page $page
+ * @return string
+ */
+ public function render_index_page(index_page $page) {
+ $data = $page->export_for_template($this);
+ return parent::render_from_template('core_group/index', $data);
+ }
+}
diff --git a/group/index.php b/group/index.php
index 6571f545d91..8150e196f00 100644
--- a/group/index.php
+++ b/group/index.php
@@ -61,6 +61,7 @@ $context = context_course::instance($course->id);
require_capability('moodle/course:managegroups', $context);
$PAGE->requires->js('/group/clientlib.js');
+$PAGE->requires->js('/group/module.js');
// Check for multiple/no group errors
if (!$singlegroup) {
@@ -152,41 +153,23 @@ echo $OUTPUT->header();
$currenttab = 'groups';
require('tabs.php');
-$disabled = 'disabled="disabled"';
-
-// Some buttons are enabled if single group selected.
-$showaddmembersform_disabled = $singlegroup ? '' : $disabled;
-$showeditgroupsettingsform_disabled = $singlegroup ? '' : $disabled;
-$deletegroup_disabled = count($groupids) > 0 ? '' : $disabled;
-
echo $OUTPUT->heading(format_string($course->shortname, true, array('context' => $context)) .' '.$strgroups, 3);
-echo ''."\n";
-
-$PAGE->requires->js_init_call('M.core_group.init_index', array($CFG->wwwroot, $courseid));
-$PAGE->requires->js_init_call('M.core_group.groupslist', array($preventgroupremoval));
+$disableaddedit = !$singlegroup;
+$disabledelete = !empty($groupids);
+$renderable = new \core_group\output\index_page($courseid, $groupoptions, $selectedname, $members, $disableaddedit, $disabledelete,
+ $preventgroupremoval);
+$output = $PAGE->get_renderer('core_group');
+echo $output->render($renderable);
echo $OUTPUT->footer();
diff --git a/group/templates/index.mustache b/group/templates/index.mustache
new file mode 100644
index 00000000000..fb8be7f75eb
--- /dev/null
+++ b/group/templates/index.mustache
@@ -0,0 +1,145 @@
+{{!
+ 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 .
+}}
+{{!
+ @template core_group/index
+
+ Template for the Groups page.
+
+ Classes required for JS:
+ * none
+
+ Data attributes required for JS:
+ * none
+
+ Context variables required for this template:
+ * courseid int The course ID.
+ * selectedgroup string The initially selected group.
+ * editgroupsettingsdisabled bool Whether to disable the "Edit group settings" button on load.
+ * deletegroupdisabled bool Whether to disable the "Delete selected group" button on load.
+ * addmembersdisabled bool Whether to disable the "Add/remove users" button on load.
+ * groups array The list of groups.
+ * members array The list of members, grouped based on roles.
+ * undeletablegroups string A JSON string containing an array of group IDs that a user cannot delete.
+
+ Example context (json):
+ {
+ "courseid": "1",
+ "selectedgroup": "Group 1 (3)",
+ "editgroupsettingsdisabled": false,
+ "deletegroupdisabled": false,
+ "addmembersdisabled": false,
+ "groups": [
+ {
+ "value": "1",
+ "text": "Group 1 (3)",
+ "selected": true
+ },
+ {
+ "value": "2",
+ "text": "Group 2 (2)"
+ }
+ ],
+ "members": [
+ {
+ "role": "Student",
+ "rolemembers": [
+ {
+ "value": "1",
+ "text": "John Doe"
+ },
+ {
+ "value": "2",
+ "text": "Jane Doe"
+ },
+ {
+ "value": "3",
+ "text": "John Smith"
+ }
+ ]
+ }
+ ],
+ "undeletablegroups": "[1: true, 3: true]"
+ }
+}}
+
+{{#js}}
+ require(['jquery', 'core/yui'], function($) {
+ $("#groups").change(function() {
+ M.core_group.membersCombo.refreshMembers();
+ });
+ M.core_group.init_index(Y, "{{wwwroot}}", {{courseid}});
+ var undeletableGroups = JSON.parse('{{{undeletablegroups}}}');
+ M.core_group.groupslist(Y, undeletableGroups);
+ });
+{{/js}}
From 2a477bf08e5eab1615775cc9b76846b6cece86ae Mon Sep 17 00:00:00 2001
From: Mark Sharp
Date: Mon, 5 Jun 2017 09:41:42 +0100
Subject: [PATCH 16/38] MDL-59125 filter_urltolink: ignoretags on nolink span
---
filter/urltolink/filter.php | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/filter/urltolink/filter.php b/filter/urltolink/filter.php
index b232edae8b8..211e149e837 100644
--- a/filter/urltolink/filter.php
+++ b/filter/urltolink/filter.php
@@ -73,8 +73,8 @@ class filter_urltolink extends moodle_text_filter {
//
//<a href="blah">
//<a href="blah">
- $filterignoretagsopen = array(']+?>');
- $filterignoretagsclose = array('');
+ $filterignoretagsopen = array(']+?>', ']+?class="nolink"[^>]*?>');
+ $filterignoretagsclose = array('', '');
filter_save_ignore_tags($text,$filterignoretagsopen,$filterignoretagsclose,$ignoretags);
// Check if we support unicode modifiers in regular expressions. Cache it.
@@ -174,4 +174,3 @@ function filter_urltolink_img_callback($link) {
}
return '';
}
-
From 450d15d159a2c13d860ca9ffcd9c0df6f74e7119 Mon Sep 17 00:00:00 2001
From: Marina Glancy
Date: Fri, 16 Jun 2017 15:52:42 +0800
Subject: [PATCH 17/38] MDL-59125 filter_urltolink: respect nolink span,
unittest
---
filter/urltolink/tests/filter_test.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/filter/urltolink/tests/filter_test.php b/filter/urltolink/tests/filter_test.php
index 0ae7f891cff..1dca5b7f74a 100644
--- a/filter/urltolink/tests/filter_test.php
+++ b/filter/urltolink/tests/filter_test.php
@@ -174,6 +174,9 @@ class filter_urltolink_filter_testcase extends basic_testcase {
'' => '',
'www.google.com' => 'www.google.com',
'http://nolandforzombies.com Zombies FTW http://aliens.org' => 'http://nolandforzombies.comZombies FTWhttp://aliens.org',
+ // Test 'nolink' class.
+ 'URL: http://moodle.org' => 'URL: http://moodle.org',
+ 'URL: http://moodle.org' => 'URL: http://moodle.org',
//URLs in Javascript. Commented out as part of MDL-21183
//'var url="http://moodle.org";'=>'var url="http://moodle.org";',
//'var url = "http://moodle.org";'=>'var url = "http://moodle.org";',
From 4acb33f67b64af0e875598eca60133d6801c5ba9 Mon Sep 17 00:00:00 2001
From: Tobias Reischmann
Date: Wed, 7 Jun 2017 12:43:22 +0200
Subject: [PATCH 18/38] MDL-59173 tablelib.php: changed default of $params in
set_sql to array()
Default of $params = null leads to a problem in query_db().
There this value is used in array_merge, which can not handle null
values. If null is passed for one of the params the outcome will be null
independent of the value of the second param!
---
lib/tablelib.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/tablelib.php b/lib/tablelib.php
index 84d077b5011..4dd84f8de56 100644
--- a/lib/tablelib.php
+++ b/lib/tablelib.php
@@ -1545,7 +1545,7 @@ class table_sql extends flexible_table {
* Of course you can use sub-queries, JOINS etc. by putting them in the
* appropriate clause of the query.
*/
- function set_sql($fields, $from, $where, array $params = NULL) {
+ function set_sql($fields, $from, $where, array $params = array()) {
$this->sql = new stdClass();
$this->sql->fields = $fields;
$this->sql->from = $from;
From e00e67319598bb955e48cf55fecbcfc0bce87f80 Mon Sep 17 00:00:00 2001
From: Simey Lameze
Date: Wed, 14 Jun 2017 12:26:35 +0800
Subject: [PATCH 19/38] MDL-59230 block_myoverview: add missing core
notification module
---
blocks/myoverview/amd/build/tab_preferences.min.js | 2 +-
blocks/myoverview/amd/src/tab_preferences.js | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/blocks/myoverview/amd/build/tab_preferences.min.js b/blocks/myoverview/amd/build/tab_preferences.min.js
index 2bfb8fe06b0..da5bd970f13 100644
--- a/blocks/myoverview/amd/build/tab_preferences.min.js
+++ b/blocks/myoverview/amd/build/tab_preferences.min.js
@@ -1 +1 @@
-define(["jquery","core/ajax","core/custom_interaction_events"],function(a,b,c){var d=function(d){c.define(d,[c.events.activate]),d.on(c.events.activate,"[data-toggle='tab']",function(c){var d=a(c.currentTarget).data("tabname");"function"==typeof window.history.pushState&&window.history.pushState(null,null,"?myoverviewtab="+d);var e={methodname:"core_user_update_user_preferences",args:{preferences:[{type:"block_myoverview_last_tab",value:d}]}};b.call([e])[0].fail(Notification.exception)})};return{registerEventListeners:d}});
\ No newline at end of file
+define(["jquery","core/ajax","core/custom_interaction_events","core/notification"],function(a,b,c,d){var e=function(e){c.define(e,[c.events.activate]),e.on(c.events.activate,"[data-toggle='tab']",function(c){var e=a(c.currentTarget).data("tabname");"function"==typeof window.history.pushState&&window.history.pushState(null,null,"?myoverviewtab="+e);var f={methodname:"core_user_update_user_preferences",args:{preferences:[{type:"block_myoverview_last_tab",value:e}]}};b.call([f])[0].fail(d.exception)})};return{registerEventListeners:e}});
\ No newline at end of file
diff --git a/blocks/myoverview/amd/src/tab_preferences.js b/blocks/myoverview/amd/src/tab_preferences.js
index f6afc1b6193..25ac2eefa3d 100644
--- a/blocks/myoverview/amd/src/tab_preferences.js
+++ b/blocks/myoverview/amd/src/tab_preferences.js
@@ -21,7 +21,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-define(['jquery', 'core/ajax', 'core/custom_interaction_events'], function($, Ajax, CustomEvents) {
+define(['jquery', 'core/ajax', 'core/custom_interaction_events',
+ 'core/notification'], function($, Ajax, CustomEvents, Notification) {
/**
* Registers an event that saves the user's tab preference when switching between them.
From 64b6651cfa2a8d6086f7edb76d7749c2bf9b8e55 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Mudr=C3=A1k?=
Date: Fri, 16 Jun 2017 13:36:32 +0200
Subject: [PATCH 20/38] MDL-59269 lang: Fix ability to uninstall certain
language packs
In the issue MDL-39319 (6ddf92c77), the ability to uninstall multiple
language packs at once was added. By a mistake, the PARAM_ALPHAEXT was
used as paramater type for the dash-separated list of language packs to
be uninstalled. Language packs with a number in the name (such as
en_us_k12) do not pass the ALPHAEXT cleaning.
This patch changes the parameter cleaning to PARAM_SAFEPATH which is
more appropriate for the given scenario as language code themselves must
be SAFEDIRs.
---
admin/tool/langimport/index.php | 10 ++++++----
.../moodle-core-languninstallconfirm-debug.js | 2 +-
.../moodle-core-languninstallconfirm-min.js | 2 +-
.../moodle-core-languninstallconfirm.js | 2 +-
.../languninstallconfirm/js/languninstallconfirm.js | 2 +-
5 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/admin/tool/langimport/index.php b/admin/tool/langimport/index.php
index 0e98a5d2de4..92a09dad241 100644
--- a/admin/tool/langimport/index.php
+++ b/admin/tool/langimport/index.php
@@ -40,7 +40,7 @@ if (empty($CFG->langotherroot)) {
$mode = optional_param('mode', 0, PARAM_INT); // action
$pack = optional_param_array('pack', array(), PARAM_SAFEDIR); // pack to install
$uninstalllang = optional_param_array('uninstalllang', array(), PARAM_LANG);// installed pack to uninstall
-$confirmtounistall = optional_param('confirmtouninstall', '', PARAM_ALPHAEXT); // uninstallation confirmation
+$confirmtounistall = optional_param('confirmtouninstall', '', PARAM_SAFEPATH); // uninstallation confirmation
$purgecaches = optional_param('purgecaches', false, PARAM_BOOL); // explicit caches reset
if ($purgecaches) {
@@ -74,7 +74,7 @@ if ($mode == DELETION_OF_SELECTED_LANG and (!empty($uninstalllang) or !empty($co
// Actually deleting languages, languages to delete are passed as GET parameter as string
// ...need to populate them to array.
if (empty($uninstalllang)) {
- $uninstalllang = explode('-', $confirmtounistall);
+ $uninstalllang = explode('/', $confirmtounistall);
}
if (in_array('en', $uninstalllang)) {
@@ -84,8 +84,10 @@ if ($mode == DELETION_OF_SELECTED_LANG and (!empty($uninstalllang) or !empty($co
} else if (empty($confirmtounistall) and confirm_sesskey()) { // User chose langs to be deleted, show confirmation.
echo $OUTPUT->header();
echo $OUTPUT->confirm(get_string('uninstallconfirm', 'tool_langimport', implode(', ', $uninstalllang)),
- 'index.php?mode='.DELETION_OF_SELECTED_LANG.'&confirmtouninstall='.implode('-', $uninstalllang),
- 'index.php');
+ new moodle_url($PAGE->url, array(
+ 'mode' => DELETION_OF_SELECTED_LANG,
+ 'confirmtouninstall' => implode('/', $uninstalllang),
+ )), $PAGE->url);
echo $OUTPUT->footer();
die;
diff --git a/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm-debug.js b/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm-debug.js
index d12bfd2320e..6f50f4c2c34 100644
--- a/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm-debug.js
+++ b/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm-debug.js
@@ -98,7 +98,7 @@ Y.extend(Confirmation, Y.Base, {
_uninstall: function(e, langCodes) {
Y.config.win.location.href = this.get('uninstallUrl') + '?mode=4' +
'&sesskey=' + M.cfg.sesskey +
- '&confirmtouninstall=' + langCodes.join('-');
+ '&confirmtouninstall=' + langCodes.join('/');
}
});
diff --git a/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm-min.js b/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm-min.js
index fd52350bcd1..94a7844dd2a 100644
--- a/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm-min.js
+++ b/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm-min.js
@@ -1 +1 @@
-YUI.add("moodle-core-languninstallconfirm",function(e,t){function n(){n.superclass.constructor.apply(this,arguments)}var r={UNINSTALLBUTTON:"#languninstallbutton",UNINSTALLSELECT:"#menuuninstalllang option",ENGLISHOPTION:"#menuuninstalllang option[value='en']"};n.NAME=t,n.ATTRS={uninstallUrl:{validator:e.Lang.isString}},e.extend(n,e.Base,{initializer:function(){e.one(r.UNINSTALLBUTTON).on("click",this._confirm,this)},_confirm:function(t){t.preventDefault();var n=[],i=[];e.all(r.UNINSTALLSELECT).each(function(e){e.get("selected")&&(n.push(e.getAttribute("value")),i.push(e.get("text")))});if(n.length===0){(new M.core.alert({message:M.util.get_string("selectlangs","tool_langimport")})).show();return}if(n.indexOf("en")>-1){e.one(r.ENGLISHOPTION).set("selected",!1),(new M.core.alert({message:M.util.get_string("noenglishuninstall","tool_langimport")})).show();return}var s={modal:!0,visible:!1,centered:!0,title:M.util.get_string("uninstall","tool_langimport"),question:M.util.get_string("uninstallconfirm","tool_langimport",i.join(", "))};(new M.core.confirm(s)).show().on("complete-yes",this._uninstall,this,n)},_uninstall:function(t,n){e.config.win.location.href=this.get("uninstallUrl")+"?mode=4"+"&sesskey="+M.cfg.sesskey+"&confirmtouninstall="+n.join("-")}}),e.namespace("M.core.languninstallconfirm").Confirmation=n,e.namespace("M.core.languninstallconfirm").init=function(e){return new n(e)}},"@VERSION@",{requires:["base","node","moodle-core-notification-confirm","moodle-core-notification-alert"]});
+YUI.add("moodle-core-languninstallconfirm",function(e,t){function n(){n.superclass.constructor.apply(this,arguments)}var r={UNINSTALLBUTTON:"#languninstallbutton",UNINSTALLSELECT:"#menuuninstalllang option",ENGLISHOPTION:"#menuuninstalllang option[value='en']"};n.NAME=t,n.ATTRS={uninstallUrl:{validator:e.Lang.isString}},e.extend(n,e.Base,{initializer:function(){e.one(r.UNINSTALLBUTTON).on("click",this._confirm,this)},_confirm:function(t){t.preventDefault();var n=[],i=[];e.all(r.UNINSTALLSELECT).each(function(e){e.get("selected")&&(n.push(e.getAttribute("value")),i.push(e.get("text")))});if(n.length===0){(new M.core.alert({message:M.util.get_string("selectlangs","tool_langimport")})).show();return}if(n.indexOf("en")>-1){e.one(r.ENGLISHOPTION).set("selected",!1),(new M.core.alert({message:M.util.get_string("noenglishuninstall","tool_langimport")})).show();return}var s={modal:!0,visible:!1,centered:!0,title:M.util.get_string("uninstall","tool_langimport"),question:M.util.get_string("uninstallconfirm","tool_langimport",i.join(", "))};(new M.core.confirm(s)).show().on("complete-yes",this._uninstall,this,n)},_uninstall:function(t,n){e.config.win.location.href=this.get("uninstallUrl")+"?mode=4"+"&sesskey="+M.cfg.sesskey+"&confirmtouninstall="+n.join("/")}}),e.namespace("M.core.languninstallconfirm").Confirmation=n,e.namespace("M.core.languninstallconfirm").init=function(e){return new n(e)}},"@VERSION@",{requires:["base","node","moodle-core-notification-confirm","moodle-core-notification-alert"]});
diff --git a/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm.js b/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm.js
index d12bfd2320e..6f50f4c2c34 100644
--- a/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm.js
+++ b/lib/yui/build/moodle-core-languninstallconfirm/moodle-core-languninstallconfirm.js
@@ -98,7 +98,7 @@ Y.extend(Confirmation, Y.Base, {
_uninstall: function(e, langCodes) {
Y.config.win.location.href = this.get('uninstallUrl') + '?mode=4' +
'&sesskey=' + M.cfg.sesskey +
- '&confirmtouninstall=' + langCodes.join('-');
+ '&confirmtouninstall=' + langCodes.join('/');
}
});
diff --git a/lib/yui/src/languninstallconfirm/js/languninstallconfirm.js b/lib/yui/src/languninstallconfirm/js/languninstallconfirm.js
index 88eead86e08..98d87ea2019 100644
--- a/lib/yui/src/languninstallconfirm/js/languninstallconfirm.js
+++ b/lib/yui/src/languninstallconfirm/js/languninstallconfirm.js
@@ -96,7 +96,7 @@ Y.extend(Confirmation, Y.Base, {
_uninstall: function(e, langCodes) {
Y.config.win.location.href = this.get('uninstallUrl') + '?mode=4' +
'&sesskey=' + M.cfg.sesskey +
- '&confirmtouninstall=' + langCodes.join('-');
+ '&confirmtouninstall=' + langCodes.join('/');
}
});
From fc684bce4b6de3aed3fc435994095abbaf0a2f50 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luca=20B=C3=B6sch?=
Date: Fri, 19 May 2017 13:13:31 +0200
Subject: [PATCH 21/38] MDL-58766 css: clean theme block alignment
---
theme/bootstrapbase/less/moodle/blocks.less | 9 +++++++++
theme/bootstrapbase/style/moodle.css | 3 +++
2 files changed, 12 insertions(+)
diff --git a/theme/bootstrapbase/less/moodle/blocks.less b/theme/bootstrapbase/less/moodle/blocks.less
index c42131dba54..68c70daa83b 100644
--- a/theme/bootstrapbase/less/moodle/blocks.less
+++ b/theme/bootstrapbase/less/moodle/blocks.less
@@ -53,6 +53,15 @@
display: inline;
}
}
+ p {
+ &.hasicon {
+ img {
+ &.icon {
+ padding-right: 0;
+ }
+ }
+ }
+ }
}
.footer {
margin-bottom: 4px;
diff --git a/theme/bootstrapbase/style/moodle.css b/theme/bootstrapbase/style/moodle.css
index fa74dbd2c8a..d205064187f 100644
--- a/theme/bootstrapbase/style/moodle.css
+++ b/theme/bootstrapbase/style/moodle.css
@@ -15873,6 +15873,9 @@ body {
margin-left: 5px;
display: inline;
}
+.block .content p.hasicon img.icon {
+ padding-right: 0;
+}
.block .footer {
margin-bottom: 4px;
display: block;
From ff2dab456642284743c960778589a80f364819d3 Mon Sep 17 00:00:00 2001
From: Vladimir Zhirov
Date: Sat, 20 May 2017 20:43:51 +0400
Subject: [PATCH 22/38] MDL-59005 resource: fixed zip extraction for filenames
in CP-1251/CP-866
---
lib/filestorage/zip_archive.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/filestorage/zip_archive.php b/lib/filestorage/zip_archive.php
index b7d0fd68dde..21313143642 100644
--- a/lib/filestorage/zip_archive.php
+++ b/lib/filestorage/zip_archive.php
@@ -662,6 +662,7 @@ class zip_archive extends file_archive {
case 'ISO-8859-6': $encoding = 'CP720'; break;
case 'ISO-8859-7': $encoding = 'CP737'; break;
case 'ISO-8859-8': $encoding = 'CP862'; break;
+ case 'WINDOWS-1251': $encoding = 'CP866'; break;
case 'EUC-JP':
case 'UTF-8':
if ($winchar = get_string('localewincharset', 'langconfig')) {
From 46f68f026edb614ae4cf6adfe80cdd45e77cfa7e Mon Sep 17 00:00:00 2001
From: John Okely
Date: Mon, 12 Jun 2017 11:21:38 +0800
Subject: [PATCH 23/38] MDL-58310 message: No longer need to supress errors
from messaging
---
message/amd/build/message_repository.min.js | 2 +-
message/amd/src/message_repository.js | 6 ++----
.../output/popup/amd/build/notification_repository.min.js | 2 +-
message/output/popup/amd/src/notification_repository.js | 6 ++----
4 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/message/amd/build/message_repository.min.js b/message/amd/build/message_repository.min.js
index bded03758d5..5f20161d194 100644
--- a/message/amd/build/message_repository.min.js
+++ b/message/amd/build/message_repository.min.js
@@ -1 +1 @@
-define(["jquery","core/ajax","core/notification","core/log"],function(a,b,c,d){var e=function(a){"undefined"==typeof a.limit&&(a.limit=0),"undefined"==typeof a.offset&&(a.offset=0),a.limitfrom=a.offset,a.limitnum=a.limit,delete a.limit,delete a.offset;var d={methodname:"core_message_data_for_messagearea_conversations",args:a},e=b.call([d])[0];return e.fail(c.exception),e},f=function(a){var c={methodname:"core_message_get_unread_conversations_count",args:a},e=b.call([c])[0];return e.fail(function(a){d.error("Could not retrieve unread message count: "+a.message)}),e},g=function(a){var d={methodname:"core_message_mark_all_messages_as_read",args:a},e=b.call([d])[0];return e.fail(c.exception),e};return{query:e,countUnreadConversations:f,markAllAsRead:g}});
\ No newline at end of file
+define(["jquery","core/ajax","core/notification"],function(a,b,c){var d=function(a){"undefined"==typeof a.limit&&(a.limit=0),"undefined"==typeof a.offset&&(a.offset=0),a.limitfrom=a.offset,a.limitnum=a.limit,delete a.limit,delete a.offset;var d={methodname:"core_message_data_for_messagearea_conversations",args:a},e=b.call([d])[0];return e.fail(c.exception),e},e=function(a){var d={methodname:"core_message_get_unread_conversations_count",args:a},e=b.call([d])[0];return e.fail(c.exception),e},f=function(a){var d={methodname:"core_message_mark_all_messages_as_read",args:a},e=b.call([d])[0];return e.fail(c.exception),e};return{query:d,countUnreadConversations:e,markAllAsRead:f}});
\ No newline at end of file
diff --git a/message/amd/src/message_repository.js b/message/amd/src/message_repository.js
index b81eae6043e..6c0ee94f039 100644
--- a/message/amd/src/message_repository.js
+++ b/message/amd/src/message_repository.js
@@ -22,7 +22,7 @@
* @copyright 2016 Ryan Wyllie
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-define(['jquery', 'core/ajax', 'core/notification', 'core/log'], function($, Ajax, Notification, Log) {
+define(['jquery', 'core/ajax', 'core/notification'], function($, Ajax, Notification) {
/**
* Retrieve a list of messages from the server.
*
@@ -72,9 +72,7 @@ define(['jquery', 'core/ajax', 'core/notification', 'core/log'], function($, Aja
var promise = Ajax.call([request])[0];
- promise.fail(function(e) {
- Log.error('Could not retrieve unread message count: ' + e.message);
- });
+ promise.fail(Notification.exception);
return promise;
};
diff --git a/message/output/popup/amd/build/notification_repository.min.js b/message/output/popup/amd/build/notification_repository.min.js
index beb592ec1cc..6d076df7bf4 100644
--- a/message/output/popup/amd/build/notification_repository.min.js
+++ b/message/output/popup/amd/build/notification_repository.min.js
@@ -1 +1 @@
-define(["core/ajax","core/notification","core/log"],function(a,b,c){var d=function(c){"undefined"==typeof c.limit&&(c.limit=20),"undefined"==typeof c.offset&&(c.offset=0);var d={methodname:"message_popup_get_popup_notifications",args:c},e=a.call([d])[0];return e.fail(b.exception),e},e=function(b){var d={methodname:"message_popup_get_unread_popup_notification_count",args:b},e=a.call([d])[0];return e.fail(function(a){c.error("Could not retrieve notifications count: "+a.message)}),e},f=function(c){var d={methodname:"core_message_mark_all_notifications_as_read",args:c},e=a.call([d])[0];return e.fail(b.exception),e},g=function(c,d){var e={messageid:c};d&&(e.timeread=d);var f={methodname:"core_message_mark_message_read",args:e},g=a.call([f])[0];return g.fail(b.exception),g};return{query:d,countUnread:e,markAllAsRead:f,markAsRead:g}});
\ No newline at end of file
+define(["core/ajax","core/notification"],function(a,b){var c=function(c){"undefined"==typeof c.limit&&(c.limit=20),"undefined"==typeof c.offset&&(c.offset=0);var d={methodname:"message_popup_get_popup_notifications",args:c},e=a.call([d])[0];return e.fail(b.exception),e},d=function(c){var d={methodname:"message_popup_get_unread_popup_notification_count",args:c},e=a.call([d])[0];return e.fail(b.exception),e},e=function(c){var d={methodname:"core_message_mark_all_notifications_as_read",args:c},e=a.call([d])[0];return e.fail(b.exception),e},f=function(c,d){var e={messageid:c};d&&(e.timeread=d);var f={methodname:"core_message_mark_message_read",args:e},g=a.call([f])[0];return g.fail(b.exception),g};return{query:c,countUnread:d,markAllAsRead:e,markAsRead:f}});
\ No newline at end of file
diff --git a/message/output/popup/amd/src/notification_repository.js b/message/output/popup/amd/src/notification_repository.js
index 093238a9249..2fdb83ea6d0 100644
--- a/message/output/popup/amd/src/notification_repository.js
+++ b/message/output/popup/amd/src/notification_repository.js
@@ -22,7 +22,7 @@
* @copyright 2016 Ryan Wyllie
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-define(['core/ajax', 'core/notification', 'core/log'], function(Ajax, Notification, Log) {
+define(['core/ajax', 'core/notification'], function(Ajax, Notification) {
/**
* Retrieve a list of notifications from the server.
*
@@ -64,9 +64,7 @@ define(['core/ajax', 'core/notification', 'core/log'], function(Ajax, Notificati
var promise = Ajax.call([request])[0];
- promise.fail(function(e) {
- Log.error('Could not retrieve notifications count: ' + e.message);
- });
+ promise.fail(Notification.exception);
return promise;
};
From 671be2bedba7393123a8a3422865612e40b8c6f2 Mon Sep 17 00:00:00 2001
From: John Okely
Date: Mon, 29 May 2017 08:30:24 +0800
Subject: [PATCH 24/38] MDL-58310 ajax: suppress errors upon page unload
---
lib/amd/build/ajax.min.js | 2 +-
lib/amd/src/ajax.js | 15 +++++++++++++--
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/lib/amd/build/ajax.min.js b/lib/amd/build/ajax.min.js
index 936d338c377..96fcee8fbe6 100644
--- a/lib/amd/build/ajax.min.js
+++ b/lib/amd/build/ajax.min.js
@@ -1 +1 @@
-define(["jquery","core/config"],function(a,b){var c=function(a){var b,c,d=this,e=null,f=0;for(f=0;f
Date: Mon, 8 May 2017 09:49:34 +0800
Subject: [PATCH 25/38] MDL-58808 fontawesome: nav and settings blocks
---
.../amd/build/ajax_response_renderer.min.js | 2 +-
.../amd/src/ajax_response_renderer.js | 57 ++++++++++---------
blocks/navigation/styles.css | 2 +-
blocks/settings/styles.css | 2 +-
.../output/icon_system_fontawesome.php | 4 +-
theme/boost/scss/moodle/blocks.scss | 42 ++++++++++++++
6 files changed, 78 insertions(+), 31 deletions(-)
diff --git a/blocks/navigation/amd/build/ajax_response_renderer.min.js b/blocks/navigation/amd/build/ajax_response_renderer.min.js
index 4c6949207c8..02578ec2d3c 100644
--- a/blocks/navigation/amd/build/ajax_response_renderer.min.js
+++ b/blocks/navigation/amd/build/ajax_response_renderer.min.js
@@ -1 +1 @@
-define(["jquery"],function(a){function b(d,e){var f=a("
");f.attr("role","group"),f.attr("aria-hidden",!0),a.each(e,function(d,e){if("object"==typeof e){var g=a(""),h=a(""),i=e.id||e.key+"_tree_item",j=null,k=!(!e.expandable&&!e.haschildren);if(h.addClass("tree_item"),h.attr("id",i),h.attr("role","treeitem"),h.attr("tabindex","-1"),e.requiresajaxloading&&(h.attr("data-requires-ajax",!0),h.attr("data-node-id",e.id),h.attr("data-node-key",e.key),h.attr("data-node-type",e.type)),k&&(g.addClass("collapsed contains_branch"),h.attr("aria-expanded",!1),h.addClass("branch")),!e.icon||k&&e.type!==c.ACTIVITY&&e.type!==c.RESOURCE||(g.addClass("item_with_icon"),h.addClass("hasicon"),j=a(""),j.attr("alt",e.icon.alt),j.attr("title",e.icon.title),j.attr("src",M.util.image_url(e.icon.pix,e.icon.component)),a.each(e.icon.classes,function(a,b){j.addClass(b)})),e.link){var l=a('');j?(l.append(j),l.append(''+e.name+"")):l.append(e.name),e.hidden&&l.addClass("dimmed"),h.append(l)}else{var m=a("");j?(m.append(j),m.append(''+e.name+"")):m.append(e.name),e.hidden&&m.addClass("dimmed"),h.append(m)}g.append(h),f.append(g),e.children&&e.children.length?b(h,e.children):k&&!e.requiresajaxloading&&(g.removeClass("contains_branch"),h.addClass("emptybranch"))}}),d.parent().append(f);var g=d.attr("id")+"_group";f.attr("id",g),d.attr("aria-owns",g),d.attr("role","treeitem")}var c={ACTIVITY:40,RESOURCE:50};return{render:function(a,c){if(c.children&&c.children.length){b(a,c.children);var d=a.children("[role='treeitem']").first(),e=a.find("#"+d.attr("aria-owns"));d.attr("aria-expanded",!0),e.attr("aria-hidden",!1)}else a.parent().hasClass("contains_branch")&&(a.parent().removeClass("contains_branch"),a.addClass("emptybranch"))}}});
\ No newline at end of file
+define(["jquery","core/templates","core/notification","core/url"],function(a,b,c,d){function e(g,h){var i=a("
");i.attr("role","group"),i.attr("aria-hidden",!0),a.each(h,function(g,h){if("object"==typeof h){var j=a(""),k=a(""),l=h.id||h.key+"_tree_item",m=null,n=!(!h.expandable&&!h.haschildren);k.addClass("tree_item"),k.attr("id",l),k.attr("role","treeitem"),k.attr("tabindex","-1"),h.requiresajaxloading&&(k.attr("data-requires-ajax",!0),k.attr("data-node-id",h.id),k.attr("data-node-key",h.key),k.attr("data-node-type",h.type)),n&&(j.addClass("collapsed contains_branch"),k.attr("aria-expanded",!1),k.addClass("branch"));var o=null;if(h.link){var p=a('');o=p,p.append(''+h.name+""),h.hidden&&p.addClass("dimmed"),k.append(p)}else{var q=a("");o=q,q.append(''+h.name+""),h.hidden&&q.addClass("dimmed"),k.append(q)}!h.icon||n&&h.type!==f.ACTIVITY&&h.type!==f.RESOURCE||(j.addClass("item_with_icon"),k.addClass("hasicon"),h.type===f.ACTIVITY||h.type===f.RESOURCE?(m=a(""),m.attr("alt",h.icon.alt),m.attr("title",h.icon.title),m.attr("src",d.imageUrl(h.icon.pix,h.icon.component)),a.each(h.icon.classes,function(a,b){m.addClass(b)}),o.prepend(m)):("moodle"==h.icon.component&&(h.icon.component="core"),b.renderPix(h.icon.pix,h.icon.component,h.icon.title).then(function(a){o.prepend(a)})["catch"](c.exception))),j.append(k),i.append(j),h.children&&h.children.length?e(k,h.children):n&&!h.requiresajaxloading&&(j.removeClass("contains_branch"),k.addClass("emptybranch"))}}),g.parent().append(i);var j=g.attr("id")+"_group";i.attr("id",j),g.attr("aria-owns",j),g.attr("role","treeitem")}var f={ACTIVITY:40,RESOURCE:50};return{render:function(a,b){if(b.children&&b.children.length){e(a,b.children);var c=a.children("[role='treeitem']").first(),d=a.find("#"+c.attr("aria-owns"));c.attr("aria-expanded",!0),d.attr("aria-hidden",!1)}else a.parent().hasClass("contains_branch")&&(a.parent().removeClass("contains_branch"),a.addClass("emptybranch"))}}});
\ No newline at end of file
diff --git a/blocks/navigation/amd/src/ajax_response_renderer.js b/blocks/navigation/amd/src/ajax_response_renderer.js
index d9357424d1f..99f2e28f1fe 100644
--- a/blocks/navigation/amd/src/ajax_response_renderer.js
+++ b/blocks/navigation/amd/src/ajax_response_renderer.js
@@ -22,7 +22,7 @@
* @copyright 2015 John Okely
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-define(['jquery'], function($) {
+define(['jquery', 'core/templates', 'core/notification', 'core/url'], function($, Templates, Notification, Url) {
// Mappings for the different types of nodes coming from the navigation.
// Copied from lib/navigationlib.php navigation_node constants.
@@ -75,28 +75,12 @@ define(['jquery'], function($) {
p.addClass('branch');
}
- if (node.icon && (!isBranch || node.type === NODETYPE.ACTIVITY || node.type === NODETYPE.RESOURCE)) {
- li.addClass('item_with_icon');
- p.addClass('hasicon');
-
- icon = $('');
- icon.attr('alt', node.icon.alt);
- icon.attr('title', node.icon.title);
- icon.attr('src', M.util.image_url(node.icon.pix, node.icon.component));
- $.each(node.icon.classes, function(index, className) {
- icon.addClass(className);
- });
- }
-
+ var eleToAddIcon = null;
if (node.link) {
var link = $('');
- if (icon) {
- link.append(icon);
- link.append('' + node.name + '');
- } else {
- link.append(node.name);
- }
+ eleToAddIcon = link;
+ link.append('' + node.name + '');
if (node.hidden) {
link.addClass('dimmed');
@@ -106,12 +90,8 @@ define(['jquery'], function($) {
} else {
var span = $('');
- if (icon) {
- span.append(icon);
- span.append('' + node.name + '');
- } else {
- span.append(node.name);
- }
+ eleToAddIcon = span;
+ span.append('' + node.name + '');
if (node.hidden) {
span.addClass('dimmed');
@@ -120,6 +100,31 @@ define(['jquery'], function($) {
p.append(span);
}
+ if (node.icon && (!isBranch || node.type === NODETYPE.ACTIVITY || node.type === NODETYPE.RESOURCE)) {
+ li.addClass('item_with_icon');
+ p.addClass('hasicon');
+
+ if (node.type === NODETYPE.ACTIVITY || node.type === NODETYPE.RESOURCE) {
+ icon = $('');
+ icon.attr('alt', node.icon.alt);
+ icon.attr('title', node.icon.title);
+ icon.attr('src', Url.imageUrl(node.icon.pix, node.icon.component));
+ $.each(node.icon.classes, function(index, className) {
+ icon.addClass(className);
+ });
+ eleToAddIcon.prepend(icon);
+ } else {
+ if (node.icon.component == 'moodle') {
+ node.icon.component = 'core';
+ }
+ Templates.renderPix(node.icon.pix, node.icon.component, node.icon.title).then(function(html) {
+ // Prepend.
+ eleToAddIcon.prepend(html);
+ return;
+ }).catch(Notification.exception);
+ }
+ }
+
li.append(p);
ul.append(li);
diff --git a/blocks/navigation/styles.css b/blocks/navigation/styles.css
index bb541f55926..2369c1af0d6 100644
--- a/blocks/navigation/styles.css
+++ b/blocks/navigation/styles.css
@@ -71,6 +71,6 @@
display: block;
}
-.block_navigation .block_tree [aria-hidden="true"] {
+.block_navigation .block_tree [aria-hidden="true"]:not(.icon) {
display: none;
}
diff --git a/blocks/settings/styles.css b/blocks/settings/styles.css
index e0c94b2bad6..3d7e1d1a3e2 100644
--- a/blocks/settings/styles.css
+++ b/blocks/settings/styles.css
@@ -58,7 +58,7 @@
display: block;
}
-.block_settings .block_tree [aria-hidden="true"] {
+.block_settings .block_tree [aria-hidden="true"]:not(.icon) {
display: none;
}
diff --git a/lib/classes/output/icon_system_fontawesome.php b/lib/classes/output/icon_system_fontawesome.php
index b047d63c47f..3d9593a1abb 100644
--- a/lib/classes/output/icon_system_fontawesome.php
+++ b/lib/classes/output/icon_system_fontawesome.php
@@ -247,7 +247,7 @@ class icon_system_fontawesome extends icon_system_font {
'core:i/mnethost' => 'fa-external-link',
'core:i/moodle_host' => 'fa-graduation-cap',
'core:i/move_2d' => 'fa-arrows',
- 'core:i/navigationitem' => 'fa-angle-right',
+ 'core:i/navigationitem' => 'fa-fw',
'core:i/ne_red_mark' => 'fa-remove',
'core:i/new' => 'fa-plus',
'core:i/news' => 'fa-newspaper-o',
@@ -280,7 +280,7 @@ class icon_system_fontawesome extends icon_system_font {
'core:i/scales' => 'fa-balance-scale',
'core:i/scheduled' => 'fa-calendar-check-o',
'core:i/search' => 'fa-search',
- 'core:i/settings' => 'fa-cogs',
+ 'core:i/settings' => 'fa-cog',
'core:i/show' => 'fa-eye-slash',
'core:i/siteevent' => 'fa-share-alt',
'core:i/star-rating' => 'fa-star',
diff --git a/theme/boost/scss/moodle/blocks.scss b/theme/boost/scss/moodle/blocks.scss
index bfa78154978..c5df38a326e 100644
--- a/theme/boost/scss/moodle/blocks.scss
+++ b/theme/boost/scss/moodle/blocks.scss
@@ -206,3 +206,45 @@ $doughnut-fill-colour: $brand-warning;
}
}
}
+
+// Show expand collapse with font-awesome.
+.block_settings .block_tree [aria-expanded="true"],
+.block_settings .block_tree [aria-expanded="true"].emptybranch,
+.block_settings .block_tree [aria-expanded="false"],
+.block_navigation .block_tree [aria-expanded="true"],
+.block_navigation .block_tree [aria-expanded="true"].emptybranch,
+.block_navigation .block_tree [aria-expanded="false"] {
+ background-image: none;
+}
+.block_settings .block_tree [aria-expanded="true"]:before,
+.block_navigation .block_tree [aria-expanded="true"]:before {
+ content: $fa-var-angle-down;
+ margin-right: 0;
+ font-size: 16px;
+ @extend .fa;
+ width: 16px;
+}
+
+.block_settings .block_tree [aria-expanded="false"]:before,
+.block_navigation .block_tree [aria-expanded="false"]:before {
+ content: $fa-var-angle-right;
+ font-size: 16px;
+ margin-right: 0;
+ @extend .fa;
+ width: 16px;
+}
+.dir-rtl {
+ .block_settings .block_tree [aria-expanded="false"]:before,
+ .block_navigation .block_tree [aria-expanded="false"]:before {
+ content: $fa-var-angle-left;
+ }
+}
+
+.block_navigation .block_tree p.hasicon,
+.block_settings .block_tree p.hasicon {
+ text-indent: -3px;
+
+ .icon {
+ margin-right: 2px;
+ }
+}
From b5ef326c03a3252f4b47184042e4acdf947ebd0f Mon Sep 17 00:00:00 2001
From: Juan Leyva
Date: Tue, 13 Jun 2017 13:01:33 +0100
Subject: [PATCH 26/38] MDL-26976 files: Display space usage message in private
files
---
lang/en/moodle.php | 1 +
user/files.php | 14 ++++++++++++++
2 files changed, 15 insertions(+)
diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index 07e154d24c6..cb129061a1a 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -1505,6 +1505,7 @@ $string['publicsitefileswarning3'] = 'Note: Files placed here can be accessed by
$string['publish'] = 'Publish';
$string['question'] = 'Question';
$string['questionsinthequestionbank'] = 'Questions in the question bank';
+$string['quotausage'] = 'You have currently used {$a->used} of your {$a->total} limit.';
$string['readinginfofrombackup'] = 'Reading info from backup';
$string['readme'] = 'README';
$string['recentactivity'] = 'Recent activity';
diff --git a/user/files.php b/user/files.php
index 32c99f4f244..dadaf619d94 100644
--- a/user/files.php
+++ b/user/files.php
@@ -82,6 +82,20 @@ if ($mform->is_cancelled()) {
echo $OUTPUT->header();
echo $OUTPUT->box_start('generalbox');
+// Show file area space usage.
+if ($maxareabytes != FILE_AREA_MAX_BYTES_UNLIMITED) {
+ $fileareainfo = file_get_file_area_info($context->id, 'user', 'private');
+ // Display message only if we have files.
+ if ($fileareainfo['filecount']) {
+ $a = (object) [
+ 'used' => display_size($fileareainfo['filesize_without_references']),
+ 'total' => display_size($maxareabytes)
+ ];
+ $quotamsg = get_string('quotausage', 'moodle', $a);
+ $notification = new \core\output\notification($quotamsg, \core\output\notification::NOTIFY_INFO);
+ echo $OUTPUT->render($notification);
+ }
+}
$mform->display();
echo $OUTPUT->box_end();
From 0f398b500d5ad4bd1eae20bc050b1fb8bcf9a13d Mon Sep 17 00:00:00 2001
From: Juan Leyva
Date: Thu, 8 Jun 2017 13:04:10 +0100
Subject: [PATCH 27/38] MDL-59160 core_group: Return if the user can access all
groups in WS
The core_group_get_activity_allowed_groups WS should be returning not
only the groups but also if the user is allowed to access all the
activity groups.
---
group/externallib.php | 3 +++
group/tests/externallib_test.php | 10 ++++++++++
lib/upgrade.txt | 2 ++
3 files changed, 15 insertions(+)
diff --git a/group/externallib.php b/group/externallib.php
index 5359a373f17..c3d25304e1e 100644
--- a/group/externallib.php
+++ b/group/externallib.php
@@ -1386,6 +1386,7 @@ class core_group_external extends external_api {
$results = array(
'groups' => $usergroups,
+ 'canaccessallgroups' => has_capability('moodle/site:accessallgroups', $context, $user),
'warnings' => $warnings
);
return $results;
@@ -1401,6 +1402,8 @@ class core_group_external extends external_api {
return new external_single_structure(
array(
'groups' => new external_multiple_structure(self::group_description()),
+ 'canaccessallgroups' => new external_value(PARAM_BOOL,
+ 'Whether the user will be able to access all the activity groups.', VALUE_OPTIONAL),
'warnings' => new external_warnings(),
)
);
diff --git a/group/tests/externallib_test.php b/group/tests/externallib_test.php
index 97a6cf93184..dcbb0ef2742 100644
--- a/group/tests/externallib_test.php
+++ b/group/tests/externallib_test.php
@@ -523,6 +523,7 @@ class core_group_externallib_testcase extends externallib_advanced_testcase {
$groups = core_group_external::get_activity_allowed_groups($cm1->id);
$groups = external_api::clean_returnvalue(core_group_external::get_activity_allowed_groups_returns(), $groups);
$this->assertCount(2, $groups['groups']);
+ $this->assertFalse($groups['canaccessallgroups']);
foreach ($groups['groups'] as $group) {
if ($group['name'] == $group1data['name']) {
@@ -539,12 +540,21 @@ class core_group_externallib_testcase extends externallib_advanced_testcase {
$groups = core_group_external::get_activity_allowed_groups($cm1->id, $student->id);
$groups = external_api::clean_returnvalue(core_group_external::get_activity_allowed_groups_returns(), $groups);
$this->assertCount(2, $groups['groups']);
+ // We are checking the $student passed as parameter so this will return false.
+ $this->assertFalse($groups['canaccessallgroups']);
// Check warnings. Trying to get groups for a user not enrolled in course.
$groups = core_group_external::get_activity_allowed_groups($cm1->id, $otherstudent->id);
$groups = external_api::clean_returnvalue(core_group_external::get_activity_allowed_groups_returns(), $groups);
$this->assertCount(1, $groups['warnings']);
+ $this->assertFalse($groups['canaccessallgroups']);
+ // Checking teacher groups.
+ $groups = core_group_external::get_activity_allowed_groups($cm1->id);
+ $groups = external_api::clean_returnvalue(core_group_external::get_activity_allowed_groups_returns(), $groups);
+ $this->assertCount(2, $groups['groups']);
+ // Teachers by default can access all groups.
+ $this->assertTrue($groups['canaccessallgroups']);
}
/**
diff --git a/lib/upgrade.txt b/lib/upgrade.txt
index 09c2839f65e..0044bd34e54 100644
--- a/lib/upgrade.txt
+++ b/lib/upgrade.txt
@@ -10,6 +10,8 @@ information provided here is intended especially for developers.
* Removed accesslib private functions: load_course_context(), load_role_access_by_context(), dedupe_user_access() (MDL-49398).
* Internal "accessdata" structure format has changed to improve ability to perform role definition caching (MDL-49398).
* Role definitions are no longer cached in user session (MDL-49398).
+* External function core_group_external::get_activity_allowed_groups now returns an additional field: canaccessallgroups.
+ It indicates whether the user will be able to access all the activity groups.
=== 3.3.1 ===
From 07782e10f12d5f6db4fa633fd697c9473e52bde7 Mon Sep 17 00:00:00 2001
From: Simey Lameze
Date: Fri, 16 Jun 2017 15:01:30 +0800
Subject: [PATCH 28/38] MDL-59270 block_myoverview: tab setting logic to main
template on clean
---
.../templates/block_myoverview/main.mustache | 20 ++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/theme/bootstrapbase/templates/block_myoverview/main.mustache b/theme/bootstrapbase/templates/block_myoverview/main.mustache
index 650eb9bc060..42577fed2eb 100644
--- a/theme/bootstrapbase/templates/block_myoverview/main.mustache
+++ b/theme/bootstrapbase/templates/block_myoverview/main.mustache
@@ -24,27 +24,33 @@
}}
+{{#js}}
+require(['jquery', 'block_myoverview/tab_preferences'], function($, TabPreferences) {
+ var root = $('#block-myoverview-view-choices-{{uniqid}}');
+ TabPreferences.registerEventListeners(root);
+});
+{{/js}}
From 63e9e382028a99704b51f00c9fa471947c69c573 Mon Sep 17 00:00:00 2001
From: Marina Glancy
Date: Fri, 26 May 2017 10:15:17 +0800
Subject: [PATCH 29/38] MDL-58911 calendar: use the same callbacks in unittests
and prod
Remove unittest-specific callbacks for checking access and displaying
the calendar events on the dashboard.
This will allow plugin developers unittest the full behavior
of how their plugins add events to the dashboard.
Reset all static caches between unittests.
---
calendar/classes/local/event/container.php | 172 ++++++++++-----------
calendar/tests/externallib_test.php | 11 +-
lib/phpunit/classes/util.php | 5 +
3 files changed, 90 insertions(+), 98 deletions(-)
diff --git a/calendar/classes/local/event/container.php b/calendar/classes/local/event/container.php
index 20b39ec5728..9ac8cbf3432 100644
--- a/calendar/classes/local/event/container.php
+++ b/calendar/classes/local/event/container.php
@@ -71,11 +71,6 @@ class container {
*/
protected static $eventretrievalstrategy;
- /**
- * @var array A list of callbacks to use.
- */
- protected static $callbacks = array();
-
/**
* @var \stdClass[] An array of cached courses to use with the event factory.
*/
@@ -91,16 +86,6 @@ class container {
*/
private static function init() {
if (empty(self::$eventfactory)) {
- // When testing the container's components, we need to make sure
- // the callback implementations in modules are not executed, since
- // we cannot control their output from PHPUnit. To do this we have
- // a set of 'testing' callbacks that the factory can use. This way
- // we know exactly how the factory behaves when being tested.
- $getcallback = function($which) {
- return self::$callbacks[PHPUNIT_TEST ? 'testing' : 'production'][$which];
- };
-
- self::initcallbacks();
self::$actionfactory = new action_factory();
self::$eventmapper = new event_mapper(
// The event mapper we return from here needs to know how to
@@ -129,8 +114,8 @@ class container {
);
self::$eventfactory = new event_factory(
- $getcallback('action'),
- $getcallback('visibility'),
+ [self::class, 'apply_component_provide_event_action'],
+ [self::class, 'apply_component_is_event_visible'],
function ($dbrow) {
// At present we only have a bail-out check for events in course modules.
if (empty($dbrow->modulename)) {
@@ -183,6 +168,19 @@ class container {
}
}
+ /**
+ * Reset all static caches, called between tests.
+ */
+ public static function reset_caches() {
+ self::$eventfactory = null;
+ self::$eventmapper = null;
+ self::$eventvault = null;
+ self::$actionfactory = null;
+ self::$eventretrievalstrategy = null;
+ self::$coursecache = [];
+ self::$modulecache = [];
+ }
+
/**
* Gets the event factory.
*
@@ -214,88 +212,74 @@ class container {
}
/**
- * Initialises the callbacks.
+ * Calls callback 'core_calendar_provide_event_action' from the component responsible for the event
*
- * There are two sets here, one is used during PHPUnit runs.
- * See the comment at the start of the init method for more
- * detail.
+ * If no callback is present or callback returns null, there is no action on the event
+ * and it will not be displayed on the dashboard.
+ *
+ * @param event_interface $event
+ * @return action_event|event_interface
*/
- private static function initcallbacks() {
- self::$callbacks = array(
- 'testing' => array(
- // Always return an action event.
- 'action' => function (event_interface $event) {
- return new action_event(
- $event,
- new \core_calendar\local\event\value_objects\action(
- 'test',
- new \moodle_url('http://example.com'),
- 420,
- true
- ));
- },
- // Always be visible.
- 'visibility' => function (event_interface $event) {
- return true;
- }
- ),
- 'production' => array(
- // This function has type event_interface -> event_interface.
- // This is enforced by the event_factory.
- 'action' => function (event_interface $event) {
- // Callbacks will get supplied a "legacy" version
- // of the event class.
- $mapper = self::$eventmapper;
- $action = null;
- if ($event->get_course_module()) {
- // TODO MDL-58866 Only activity modules currently support this callback.
- // Any other event will not be displayed on the dashboard.
- $action = component_callback(
- 'mod_' . $event->get_course_module()->get('modname'),
- 'core_calendar_provide_event_action',
- [
- $mapper->from_event_to_legacy_event($event),
- self::$actionfactory
- ]
- );
- }
+ public static function apply_component_provide_event_action(event_interface $event) {
+ // Callbacks will get supplied a "legacy" version
+ // of the event class.
+ $mapper = self::$eventmapper;
+ $action = null;
+ if ($event->get_course_module()) {
+ // TODO MDL-58866 Only activity modules currently support this callback.
+ // Any other event will not be displayed on the dashboard.
+ $action = component_callback(
+ 'mod_' . $event->get_course_module()->get('modname'),
+ 'core_calendar_provide_event_action',
+ [
+ $mapper->from_event_to_legacy_event($event),
+ self::$actionfactory
+ ]
+ );
+ }
- // If we get an action back, return an action event, otherwise
- // continue piping through the original event.
- //
- // If a module does not implement the callback, component_callback
- // returns null.
- return $action ? new action_event($event, $action) : $event;
- },
- // This function has type event_interface -> bool.
- // This is enforced by the event_factory.
- 'visibility' => function (event_interface $event) {
- $mapper = self::$eventmapper;
- $eventvisible = null;
- if ($event->get_course_module()) {
- // TODO MDL-58866 Only activity modules currently support this callback.
- $eventvisible = component_callback(
- 'mod_' . $event->get_course_module()->get('modname'),
- 'core_calendar_is_event_visible',
- [
- $mapper->from_event_to_legacy_event($event)
- ]
- );
- }
+ // If we get an action back, return an action event, otherwise
+ // continue piping through the original event.
+ //
+ // If a module does not implement the callback, component_callback
+ // returns null.
+ return $action ? new action_event($event, $action) : $event;
+ }
- // Do not display the event if there is nothing to action.
- if ($event instanceof action_event_interface && $event->get_action()->get_item_count() === 0) {
- return false;
- }
+ /**
+ * Calls callback 'core_calendar_is_event_visible' from the component responsible for the event
+ *
+ * The visibility callback is optional, if not present it is assumed as visible.
+ * If it is an actionable event but the get_item_count() returns 0 the visibility
+ * is set to false.
+ *
+ * @param event_interface $event
+ * @return bool
+ */
+ public static function apply_component_is_event_visible(event_interface $event) {
+ $mapper = self::$eventmapper;
+ $eventvisible = null;
+ if ($event->get_course_module()) {
+ // TODO MDL-58866 Only activity modules currently support this callback.
+ $eventvisible = component_callback(
+ 'mod_' . $event->get_course_module()->get('modname'),
+ 'core_calendar_is_event_visible',
+ [
+ $mapper->from_event_to_legacy_event($event)
+ ]
+ );
+ }
- // Module does not implement the callback, event should be visible.
- if (is_null($eventvisible)) {
- return true;
- }
+ // Do not display the event if there is nothing to action.
+ if ($event instanceof action_event_interface && $event->get_action()->get_item_count() === 0) {
+ return false;
+ }
- return $eventvisible ? true : false;
- }
- ),
- );
+ // Module does not implement the callback, event should be visible.
+ if (is_null($eventvisible)) {
+ return true;
+ }
+
+ return $eventvisible ? true : false;
}
}
diff --git a/calendar/tests/externallib_test.php b/calendar/tests/externallib_test.php
index 9912bcc1381..fc0ecc2effc 100644
--- a/calendar/tests/externallib_test.php
+++ b/calendar/tests/externallib_test.php
@@ -674,13 +674,15 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
*/
public function test_get_calendar_events_override() {
$user = $this->getDataGenerator()->create_user();
+ $user2 = $this->getDataGenerator()->create_user();
$teacher = $this->getDataGenerator()->create_user();
$anotheruser = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
$moduleinstance = $generator->create_instance(['course' => $course->id]);
- $this->getDataGenerator()->enrol_user($user->id, $course->id);
+ $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
+ $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
$this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
$this->resetAfterTest(true);
$this->setAdminUser();
@@ -692,11 +694,12 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
];
$now = time();
+ // Create two events - one for everybody in the course and one only for the first student.
$event1 = $this->create_calendar_event('Base event', 0, 'due', 0, $now + DAYSECS, $params + ['courseid' => $course->id]);
$event2 = $this->create_calendar_event('User event', $user->id, 'due', 0, $now + 2*DAYSECS, $params + ['courseid' => 0]);
- // Retrieve course events for teacher - only one "Base event" is returned.
- $this->setUser($teacher);
+ // Retrieve course events for the second student - only one "Base event" is returned.
+ $this->setUser($user2);
$paramevents = array('courseids' => array($course->id));
$options = array ('siteevents' => true, 'userevents' => true);
$events = core_calendar_external::get_calendar_events($paramevents, $options);
@@ -705,7 +708,7 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
$this->assertEquals(0, count($events['warnings']));
$this->assertEquals('Base event', $events['events'][0]['name']);
- // Retrieve events for user - both events are returned.
+ // Retrieve events for the first student - both events are returned.
$this->setUser($user);
$events = core_calendar_external::get_calendar_events($paramevents, $options);
$events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
diff --git a/lib/phpunit/classes/util.php b/lib/phpunit/classes/util.php
index a3997c400af..57c67c06d03 100644
--- a/lib/phpunit/classes/util.php
+++ b/lib/phpunit/classes/util.php
@@ -229,6 +229,11 @@ class phpunit_util extends testing_util {
// Reset internal users.
core_user::reset_internal_users();
+ // Clear static caches in calendar container.
+ if (class_exists('\core_calendar\local\event\container', false)) {
+ core_calendar\local\event\container::reset_caches();
+ }
+
//TODO MDL-25290: add more resets here and probably refactor them to new core function
// Reset course and module caches.
From bef5777fc45321a7dc01eecb15cbca69dfbbe1a6 Mon Sep 17 00:00:00 2001
From: Juan Leyva
Date: Mon, 12 Jun 2017 11:48:53 +0100
Subject: [PATCH 30/38] MDL-59214 webservice: Return calendar type in
get_site_info
---
lib/classes/user.php | 2 +-
webservice/externallib.php | 12 +++++++++++-
webservice/tests/externallib_test.php | 6 ++++++
webservice/upgrade.txt | 5 +++++
4 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/lib/classes/user.php b/lib/classes/user.php
index 49672295cdc..6925e0224f6 100644
--- a/lib/classes/user.php
+++ b/lib/classes/user.php
@@ -461,7 +461,7 @@ class core_user {
'choices' => array_merge(array('' => ''), get_string_manager()->get_list_of_countries(true, true)));
$fields['lang'] = array('type' => PARAM_LANG, 'null' => NULL_NOT_ALLOWED, 'default' => $CFG->lang,
'choices' => array_merge(array('' => ''), get_string_manager()->get_list_of_translations(false)));
- $fields['calendartype'] = array('type' => PARAM_NOTAGS, 'null' => NULL_NOT_ALLOWED, 'default' => $CFG->calendartype,
+ $fields['calendartype'] = array('type' => PARAM_PLUGIN, 'null' => NULL_NOT_ALLOWED, 'default' => $CFG->calendartype,
'choices' => array_merge(array('' => ''), \core_calendar\type_factory::get_list_of_calendar_types()));
$fields['theme'] = array('type' => PARAM_THEME, 'null' => NULL_NOT_ALLOWED,
'default' => theme_config::DEFAULT_THEME, 'choices' => array_merge(array('' => ''), get_list_of_themes()));
diff --git a/webservice/externallib.php b/webservice/externallib.php
index 84b0fd4b40d..b091147691e 100644
--- a/webservice/externallib.php
+++ b/webservice/externallib.php
@@ -197,6 +197,14 @@ class core_webservice_external extends external_api {
// User home page.
$siteinfo['userhomepage'] = get_home_page();
+ // Calendar.
+ $siteinfo['sitecalendartype'] = $CFG->calendartype;
+ if (empty($USER->calendartype)) {
+ $siteinfo['usercalendartype'] = $CFG->calendartype;
+ } else {
+ $siteinfo['usercalendartype'] = $USER->calendartype;
+ }
+
return $siteinfo;
}
@@ -259,7 +267,9 @@ class core_webservice_external extends external_api {
'userhomepage' => new external_value(PARAM_INT,
'the default home page for the user: 0 for the site home, 1 for dashboard',
VALUE_OPTIONAL),
- 'siteid' => new external_value(PARAM_INT, 'Site course ID', VALUE_OPTIONAL)
+ 'siteid' => new external_value(PARAM_INT, 'Site course ID', VALUE_OPTIONAL),
+ 'sitecalendartype' => new external_value(PARAM_PLUGIN, 'Calendar type set in the site.', VALUE_OPTIONAL),
+ 'usercalendartype' => new external_value(PARAM_PLUGIN, 'Calendar typed used by the user.', VALUE_OPTIONAL),
)
);
}
diff --git a/webservice/tests/externallib_test.php b/webservice/tests/externallib_test.php
index f845b622b2b..b5bea8ddb23 100644
--- a/webservice/tests/externallib_test.php
+++ b/webservice/tests/externallib_test.php
@@ -122,6 +122,12 @@ class core_webservice_externallib_testcase extends externallib_advanced_testcase
$this->assertEquals(true, $siteinfo['usercanmanageownfiles']);
$this->assertEquals(HOMEPAGE_MY, $siteinfo['userhomepage']);
+ $this->assertEquals($CFG->calendartype, $siteinfo['sitecalendartype']);
+ if (!empty($USER->calendartype)) {
+ $this->assertEquals($USER->calendartype, $siteinfo['usercalendartype']);
+ } else {
+ $this->assertEquals($CFG->calendartype, $siteinfo['usercalendartype']);
+ }
// Now as admin.
$this->setAdminUser();
diff --git a/webservice/upgrade.txt b/webservice/upgrade.txt
index 895a5f90a57..2301a7c6e24 100644
--- a/webservice/upgrade.txt
+++ b/webservice/upgrade.txt
@@ -3,6 +3,11 @@ information provided here is intended especially for developers.
This information is intended for authors of webservices, not people writing webservice clients.
+=== 3.4 ===
+
+* External function core_webservice_external::get_site_info() now returns the calendar type used in the site and
+ by the user in the sitecalendartype and usercalendartype fields.
+
=== 3.2 ===
* webservice->get_external_functions now returns the external function list ordered by name ASC.
From 58f266000988a7e60228835bc25096d875a4e3c2 Mon Sep 17 00:00:00 2001
From: Pierre Guinoiseau
Date: Thu, 11 May 2017 13:43:35 +1200
Subject: [PATCH 31/38] MDL-58892 pix: update icon for Mahara
---
pix/i/mahara_host.gif | Bin 324 -> 0 bytes
pix/i/mahara_host.png | Bin 0 -> 516 bytes
pix/i/mahara_host.svg | 15 +++++++++++++++
3 files changed, 15 insertions(+)
delete mode 100644 pix/i/mahara_host.gif
create mode 100644 pix/i/mahara_host.png
create mode 100644 pix/i/mahara_host.svg
diff --git a/pix/i/mahara_host.gif b/pix/i/mahara_host.gif
deleted file mode 100644
index 6b4225351ec47d1604ab9ec13f22d1e516a732ae..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 324
zcmZ?wbhEHb6krfwxXJ(m|Ns9_ZnsbEa7yoV&F=DyZqtlu)s1U4%J1=Av1fu$p=@A<
zLQK1QWV2dyvwB*eNnx*l>(bcb{=kGT_4qdJvI)VZlRT>@hi3F@RZjM+of6tG!@q30
zX6vlbmO0K{bAvh;n)c2Qn6S`y%2JQ{>&)k@v01iFWzj~%)jO4eR)d{DKB4%Ng^__l
zi$Mou1jtVeY>5t23sy7*ba7Z>FV2l!ZfU9U&$Sn#D>%}kO^
zp3ZgV=-eqLc8%@r>skuLxD}LYoOz|Br6qV&TAX+VCvbABDF*Y3vM@7qYe?pEaIo`e
MrUV3dIx<)T03R`34*&oF
diff --git a/pix/i/mahara_host.png b/pix/i/mahara_host.png
new file mode 100644
index 0000000000000000000000000000000000000000..c2e655d54c8e5798eece56bcb0b516f500eadfa1
GIT binary patch
literal 516
zcmV+f0{i`mP)Bi&C~tx$;I8T2LwAla}${NnqzqPeaL|0yX3pn31rH^J_q?e@V#2SQ0H;LZOx
zpjNNzRov?k)|_iE48T;iaLkF55sYK{5*@piT`nF6P0d2zyhM)-_XyK+lybzm2@)D50$H9qY=r=
zfVYDC!aqB9L{N{=IRTWbW251A3uzq4N5nE_H=B*6=l=lax|vnj7xA|M0000
+
+
From a7184670fdb36e8e01efe60ff5ef55c8317d8686 Mon Sep 17 00:00:00 2001
From: Jun Pataleta
Date: Wed, 21 Jun 2017 11:02:16 +0800
Subject: [PATCH 32/38] MDL-56979 group: Template and styles fixes
* Remove custom styles for groups since we're using default Bootstrap
styles now.
* Hidden input breaks grid layout. Moved it inside the groups column.
* Removed unnecessary 'groups' and 'members' classes. They are not being
used in JS nor CSS.
---
group/templates/index.mustache | 6 +++---
theme/boost/scss/moodle/core.scss | 3 ---
theme/boost/scss/moodle/user.scss | 15 ---------------
theme/bootstrapbase/less/moodle/core.less | 3 ---
theme/bootstrapbase/less/moodle/user.less | 15 ---------------
theme/bootstrapbase/style/moodle.css | 15 ---------------
6 files changed, 3 insertions(+), 54 deletions(-)
diff --git a/group/templates/index.mustache b/group/templates/index.mustache
index fb8be7f75eb..e68bdaf2da4 100644
--- a/group/templates/index.mustache
+++ b/group/templates/index.mustache
@@ -78,8 +78,8 @@