Compare commits

..

18 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) 54a393ab62 Moodle release 2.7.20 2017-05-07 21:32:36 +02:00
Marina Glancy debff7fe73 MDL-58740 block_course_overview: check session key
Thanks to Kukas Schmidt for initial patch
2017-05-04 08:55:16 +08:00
Marina Glancy 7ab7bd886d MDL-58670 blog: respect capability to search entries 2017-05-04 08:55:16 +08:00
Marina Glancy d4ece04082 MDL-58635 blogs: check edited blog belongs to current user 2017-05-04 08:55:16 +08:00
David Monllao d463c79ec2 weekly release 2.7.19+ 2017-05-03 10:27:36 +08:00
Andrew Nicols 6cfcfff118 MDL-58746 core: Simplify environment check 2017-05-03 09:20:29 +08:00
Andrew Nicols 7a142305cf MDL-58746 core: Add environment check for finfo 2017-05-01 13:22:49 +08:00
Dan Poltawski aa45fcf78e Merge branch 'MDL-58672_27' of git://github.com/stronk7/moodle into MOODLE_27_STABLE 2017-04-29 09:01:14 +01:00
Eloy Lafuente (stronk7) 799f198aa1 MDL-58672 timezones: Updated to 2017b 2017-04-27 20:34:05 +02:00
Eloy Lafuente (stronk7) 13ba557a2b MDL-54901 environment: pg93 & openssl 2017-04-18 04:04:18 +02:00
Eloy Lafuente (stronk7) b25797ced3 MDL-54901 environment: 3.3 base information
This is a direct copy of the 3.2 branch to
have changes under control easier in next commits.
2017-04-18 03:11:24 +02:00
Eloy Lafuente (stronk7) 008248c5b1 Moodle release 2.7.19 2017-03-11 22:15:46 +01:00
Marina Glancy b34eca2f9e MDL-58010 user: allow to update only whitelisted preferences 2017-03-10 18:12:39 +00:00
Eloy Lafuente (stronk7) 1f2a60e458 weekly release 2.7.18+ 2017-01-27 00:27:42 +01:00
Dan Poltawski 7f54185c69 Merge branch 'MDL-57639-27' of git://github.com/andrewnicols/moodle into MOODLE_27_STABLE 2017-01-24 10:11:25 +00:00
Dan Poltawski 54b3003c92 Merge branch 'MDL-57677-27-usermodified' of git://github.com/mudrd8mz/moodle into MOODLE_27_STABLE 2017-01-23 09:49:29 +00:00
Andrew Nicols 43235c6236 MDL-57639 mod_forum: Update to use correct variable name
This addresses a regression where unnecessary attributes were removed
from the old variable. This one was missed.
2017-01-19 13:49:03 +08:00
David Mudrák 3bb94d6919 MDL-57677 mod_forum: Fix wrong user displayed as the last post's author
In the recent issue MDL-56225, we started to record the current user as
the usermodified in the forum_discussions table when updating a forum
post. It made sense but it was a mistake.

Even if the current user really modifies the discussion by updating the
post, the field usermodified has actually been always interpreted and
displayed as the last post' author. Not as the last user who touched the
discussion.

This patch reverts that particular change to the previous behaviour and
adds explicit unit test for it.
2017-01-17 21:16:56 +01:00
17 changed files with 2709 additions and 2289 deletions
+176
View File
@@ -1870,4 +1870,180 @@
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="3.3" requires="2.7">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="5.5.31" />
<VENDOR name="mysql" version="5.5.31" />
<VENDOR name="postgres" version="9.3" />
<VENDOR name="mssql" version="10.0" />
<VENDOR name="oracle" version="10.2" />
</DATABASE>
<PHP version="5.6.5" level="required">
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
<ON_CHECK message="pcreunicodewarning" />
</FEEDBACK>
</PCREUNICODE>
<PHP_EXTENSIONS>
<PHP_EXTENSION name="iconv" level="required">
<FEEDBACK>
<ON_ERROR message="iconvrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="mbstring" level="optional">
<FEEDBACK>
<ON_CHECK message="mbstringrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="curl" level="required">
<FEEDBACK>
<ON_ERROR message="curlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="openssl" level="required">
<FEEDBACK>
<ON_ERROR message="opensslrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="tokenizer" level="optional">
<FEEDBACK>
<ON_CHECK message="tokenizerrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlrpc" level="optional">
<FEEDBACK>
<ON_CHECK message="xmlrpcrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="soap" level="optional">
<FEEDBACK>
<ON_CHECK message="soaprecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="ctype" level="required">
<FEEDBACK>
<ON_ERROR message="ctyperequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zip" level="required">
<FEEDBACK>
<ON_ERROR message="ziprequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zlib" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="gd" level="required">
<FEEDBACK>
<ON_ERROR message="gdrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="simplexml" level="required">
<FEEDBACK>
<ON_ERROR message="simplexmlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="spl" level="required">
<FEEDBACK>
<ON_ERROR message="splrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="pcre" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="dom" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xml" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlreader" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="intl" level="optional">
<FEEDBACK>
<ON_CHECK message="intlrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="json" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="hash" level="required"/>
<PHP_EXTENSION name="fileinfo" level="required"/>
</PHP_EXTENSIONS>
<PHP_SETTINGS>
<PHP_SETTING name="memory_limit" value="96M" level="required">
<FEEDBACK>
<ON_ERROR message="settingmemorylimit" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="file_uploads" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="settingfileuploads" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="opcache.enable" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="opcacherecommended" />
</FEEDBACK>
</PHP_SETTING>
</PHP_SETTINGS>
<CUSTOM_CHECKS>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbstorageengine" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
<FEEDBACK>
<ON_ERROR message="quizattemptsupgradedmessage" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
<FEEDBACK>
<ON_CHECK message="slashargumentswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
<FEEDBACK>
<ON_CHECK message="unsupporteddbtablerowformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
<FEEDBACK>
<ON_CHECK message="unoconvwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
<FEEDBACK>
<ON_CHECK message="libcurlwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfileformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfilepertable" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddblargeprefix" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
<FEEDBACK>
<ON_CHECK message="ishttpswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
<FEEDBACK>
<ON_CHECK message="incompleteunicodesupport" />
</FEEDBACK>
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
</COMPATIBILITY_MATRIX>
@@ -64,7 +64,7 @@ class block_course_overview extends block_base {
$content = array();
$updatemynumber = optional_param('mynumber', -1, PARAM_INT);
if ($updatemynumber >= 0) {
if ($updatemynumber >= 0 && optional_param('sesskey', '', PARAM_RAW) && confirm_sesskey()) {
block_course_overview_update_mynumber($updatemynumber);
}
@@ -125,4 +125,4 @@ class block_course_overview extends block_base {
$config = get_config('block_course_overview');
return !empty($config->showwelcomearea);
}
}
}
+1 -1
View File
@@ -82,7 +82,7 @@ function block_course_overview_get_myorder() {
// If preference was not found, look in the old location and convert if found.
$order = array();
if ($value = get_user_preferences('course_overview_course_order')) {
$order = unserialize($value);
$order = unserialize_array($value);
block_course_overview_update_myorder($order);
unset_user_preference('course_overview_course_order');
}
+1 -1
View File
@@ -191,7 +191,7 @@ class block_course_overview_renderer extends plugin_renderer_base {
for ($i = 1; $i <= $max; $i++) {
$options[$i] = $i;
}
$url = new moodle_url('/my/index.php');
$url = new moodle_url('/my/index.php', ['sesskey' => sesskey()]);
$select = new single_select($url, 'mynumber', $options, block_course_overview_get_max_user_courses(), array());
$select->set_label(get_string('numtodisplay', 'block_course_overview'));
$output .= $this->output->render($select);
+5 -5
View File
@@ -52,11 +52,11 @@ $action = (empty($id)) ? 'add' : 'edit';
$external = new stdClass();
// Check that this id exists
if (!empty($id) && !$DB->record_exists('blog_external', array('id' => $id))) {
print_error('wrongexternalid', 'blog');
} elseif (!empty($id)) {
$external = $DB->get_record('blog_external', array('id' => $id));
// Retrieve the external blog record.
if (!empty($id)) {
if (!$external = $DB->get_record('blog_external', array('id' => $id, 'userid' => $USER->id))) {
print_error('wrongexternalid', 'blog');
}
}
$strformheading = ($action == 'edit') ? get_string('editexternalblog', 'blog') : get_string('addnewexternalblog', 'blog');
+1 -1
View File
@@ -891,7 +891,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
}
// Append Search info
if (!empty($search)) {
if (!empty($search) && has_capability('moodle/blog:search', $sitecontext)) {
$headers['filters']['search'] = $search;
$blogurl->param('search', $search);
$PAGE->navbar->add(get_string('searchterm', 'blog', $search), $blogurl->out());
+1 -1
View File
@@ -1605,7 +1605,7 @@ class grade_report_grader extends grade_report {
// Try looking for old location of user setting that used to store all courses in one serialized user preference.
if (($oldcollapsedpref = get_user_preferences('grade_report_grader_collapsed_categories')) !== null) {
if ($collapsedall = @unserialize($oldcollapsedpref)) {
if ($collapsedall = unserialize_array($oldcollapsedpref)) {
// We found the old-style preference, filter out only categories that belong to this course and update the prefs.
$collapsed = static::filter_collapsed_categories($courseid, $collapsedall);
if (!empty($collapsed['aggregatesonly']) || !empty($collapsed['gradesonly'])) {
+1
View File
@@ -762,6 +762,7 @@ $string['numberofmissingstrings'] = 'Number of missing strings: {$a}';
$string['numberofstrings'] = 'Total number of strings: {$a->strings}<br />Missing: {$a->missing} ({$a->missingpercent}&nbsp;%)';
$string['opcacherecommended'] = 'PHP opcode caching improves performance and lowers memory requirements, OPcache extension is recommended and fully supported.';
$string['opensslrecommended'] = 'Installing the optional OpenSSL library is highly recommended -- it enables Moodle Networking functionality.';
$string['opensslrequired'] = 'The OpenSSL PHP extension is now required by Moodle to provide stronger cryptographic services.';
$string['opentogoogle'] = 'Open to Google';
$string['optionalmaintenancemessage'] = 'Optional maintenance message';
$string['order1'] = 'First';
+1
View File
@@ -180,6 +180,7 @@ $string['viewmyentriesaboutcourse'] = 'View my entries about this course';
$string['viewsiteentries'] = 'View all entries';
$string['viewuserentries'] = 'View all entries by {$a}';
$string['worldblogs'] = 'The world can read entries set to be world-accessible';
$string['wrongexternalid'] = 'Wrong external blog id';
$string['wrongpostid'] = 'Wrong blog post id';
$string['page-blog-edit'] = 'Blog editing pages';
$string['page-blog-index'] = 'Blog listing pages';
+52
View File
@@ -9670,6 +9670,58 @@ function get_course_display_name_for_list($course) {
}
}
/**
* Safe analogue of unserialize() that can only parse arrays
*
* Arrays may contain only integers or strings as both keys and values. Nested arrays are allowed.
* Note: If any string (key or value) has semicolon (;) as part of the string parsing will fail.
* This is a simple method to substitute unnecessary unserialize() in code and not intended to cover all possible cases.
*
* @param string $expression
* @return array|bool either parsed array or false if parsing was impossible.
*/
function unserialize_array($expression) {
$subs = [];
// Find nested arrays, parse them and store in $subs , substitute with special string.
while (preg_match('/([\^;\}])(a:\d+:\{[^\{\}]*\})/', $expression, $matches) && strlen($matches[2]) < strlen($expression)) {
$key = '--SUB' . count($subs) . '--';
$subs[$key] = unserialize_array($matches[2]);
if ($subs[$key] === false) {
return false;
}
$expression = str_replace($matches[2], $key . ';', $expression);
}
// Check the expression is an array.
if (!preg_match('/^a:(\d+):\{([^\}]*)\}$/', $expression, $matches1)) {
return false;
}
// Get the size and elements of an array (key;value;key;value;....).
$parts = explode(';', $matches1[2]);
$size = intval($matches1[1]);
if (count($parts) < $size * 2 + 1) {
return false;
}
// Analyze each part and make sure it is an integer or string or a substitute.
$value = [];
for ($i = 0; $i < $size * 2; $i++) {
if (preg_match('/^i:(\d+)$/', $parts[$i], $matches2)) {
$parts[$i] = (int)$matches2[1];
} else if (preg_match('/^s:(\d+):"(.*)"$/', $parts[$i], $matches3) && strlen($matches3[2]) == (int)$matches3[1]) {
$parts[$i] = $matches3[2];
} else if (preg_match('/^--SUB\d+--$/', $parts[$i])) {
$parts[$i] = $subs[$parts[$i]];
} else {
return false;
}
}
// Combine keys and values.
for ($i = 0; $i < $size * 2; $i += 2) {
$value[$parts[$i]] = $parts[$i+1];
}
return $value;
}
/**
* The lang_string class
*
+30
View File
@@ -2972,4 +2972,34 @@ class core_moodlelib_testcase extends advanced_testcase {
$CFG->mailprefix = 'mdl-';
$this->assertEquals(1, validate_email(generate_email_processing_address(23, $modargs)));
}
/**
* Test safe method unserialize_array().
*/
public function test_unserialize_array() {
$a = [1, 2, 3];
$this->assertEquals($a, unserialize_array(serialize($a)));
$this->assertEquals($a, unserialize_array(serialize($a)));
$a = ['a' => 1, 2 => 2, 'b' => 'cde'];
$this->assertEquals($a, unserialize_array(serialize($a)));
$this->assertEquals($a, unserialize_array(serialize($a)));
$a = ['a' => 1, 2 => 2, 'b' => 'c"d"e'];
$this->assertEquals($a, unserialize_array(serialize($a)));
$a = ['a' => 1, 2 => ['c' => 'd', 'e' => 'f'], 'b' => 'cde'];
$this->assertEquals($a, unserialize_array(serialize($a)));
// Can not unserialize if any string contains semicolons.
$a = ['a' => 1, 2 => 2, 'b' => 'c"d";e'];
$this->assertEquals(false, unserialize_array(serialize($a)));
// Can not unserialize if there are any objects.
$a = (object)['a' => 1, 2 => 2, 'b' => 'cde'];
$this->assertEquals(false, unserialize_array(serialize($a)));
$a = ['a' => 1, 2 => 2, 'b' => (object)['a' => 'cde']];
$this->assertEquals(false, unserialize_array(serialize($a)));
// Array used in the grader report.
$a = array('aggregatesonly' => [51, 34], 'gradesonly' => [21, 45, 78]);
$this->assertEquals($a, unserialize_array(serialize($a)));
}
}
+2330 -2270
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -4516,7 +4516,7 @@ function forum_update_post($newpost, $mform, &$message) {
// Last post modified tracking.
$discussion->timemodified = $post->modified;
$discussion->usermodified = $USER->id;
$discussion->usermodified = $post->userid;
if (!$post->parent) { // Post is a discussion starter - update discussion title and times too
$discussion->name = $post->subject;
@@ -4531,7 +4531,7 @@ function forum_update_post($newpost, $mform, &$message) {
forum_add_attachment($post, $forum, $cm, $mform, $message);
if (forum_tp_can_track_forums($forum) && forum_tp_is_tracked($forum)) {
forum_tp_mark_post_read($USER->id, $post, $post->forum);
forum_tp_mark_post_read($USER->id, $post, $forum->id);
}
// Let Moodle know that assessable content is uploaded (eg for plagiarism detection)
+52
View File
@@ -940,4 +940,56 @@ class mod_forum_lib_testcase extends advanced_testcase {
}
/**
* Test that {@link forum_update_post()} keeps correct forum_discussions usermodified.
*/
public function test_forum_update_post_keeps_discussions_usermodified() {
global $DB;
$this->resetAfterTest();
// Let there be light.
$teacher = self::getDataGenerator()->create_user();
$student = self::getDataGenerator()->create_user();
$course = self::getDataGenerator()->create_course();
$forum = self::getDataGenerator()->create_module('forum', (object)[
'course' => $course->id,
]);
$generator = self::getDataGenerator()->get_plugin_generator('mod_forum');
// Let the teacher start a discussion.
$discussion = $generator->create_discussion((object)[
'course' => $course->id,
'userid' => $teacher->id,
'forum' => $forum->id,
]);
// On this freshly created discussion, the teacher is the author of the last post.
$this->assertEquals($teacher->id, $DB->get_field('forum_discussions', 'usermodified', ['id' => $discussion->id]));
// Let the student reply to the teacher's post.
$reply = $generator->create_post((object)[
'course' => $course->id,
'userid' => $student->id,
'forum' => $forum->id,
'discussion' => $discussion->id,
'parent' => $discussion->firstpost,
]);
// The student should now be the last post's author.
$this->assertEquals($student->id, $DB->get_field('forum_discussions', 'usermodified', ['id' => $discussion->id]));
// Let the teacher edit the student's reply.
$this->setUser($teacher->id);
$newpost = (object)[
'id' => $reply->id,
'itemid' => 0,
'subject' => 'Amended subject',
];
forum_update_post($newpost, null, $message);
// The student should be still the last post's author.
$this->assertEquals($student->id, $DB->get_field('forum_discussions', 'usermodified', ['id' => $discussion->id]));
}
}
+32 -2
View File
@@ -203,8 +203,9 @@ class core_user_external extends external_api {
// Preferences.
if (!empty($user['preferences'])) {
$userobject = (object)$user;
foreach ($user['preferences'] as $preference) {
set_user_preference($preference['type'], $preference['value'], $user['id']);
self::set_user_preference($preference['type'], $preference['value'], $userobject);
}
}
@@ -433,7 +434,7 @@ class core_user_external extends external_api {
// Preferences.
if (!empty($user['preferences'])) {
foreach ($user['preferences'] as $preference) {
set_user_preference($preference['type'], $preference['value'], $user['id']);
self::set_user_preference($preference['type'], $preference['value'], $existinguser);
}
}
}
@@ -1176,6 +1177,35 @@ class core_user_external extends external_api {
);
}
/**
* Validates preference value and updates the user preference
*
* @param string $name
* @param string $value
* @param stdClass $user
*/
protected static function set_user_preference($name, $value, $user) {
$preferences = array(
'auth_forcepasswordchange' => PARAM_BOOL,
'htmleditor' => PARAM_COMPONENT,
'usemodchooser' => PARAM_BOOL,
'badgeprivacysetting' => PARAM_BOOL,
'blogpagesize' => PARAM_INT,
'forum_markasreadonnotification' => PARAM_INT,
'calendar_timeformat' => PARAM_NOTAGS,
'calendar_startwday' => PARAM_INT,
'calendar_maxevents' => PARAM_INT,
'calendar_lookahead' => PARAM_INT,
'calendar_persistflt' => PARAM_INT
);
if (isset($preferences[$name])) {
$value = clean_param($value, $preferences[$name]);
if ($preferences[$name] == PARAM_BOOL) {
$value = (int)$value;
}
set_user_preference($name, $value, $user);
}
}
}
/**
+20 -2
View File
@@ -478,7 +478,14 @@ class core_user_externallib_testcase extends externallib_advanced_testcase {
'email' => 'usertest1@example.com',
'description' => 'This is a description for user 1',
'city' => 'Perth',
'country' => 'au'
'country' => 'au',
'preferences' => [[
'type' => 'htmleditor',
'value' => 'atto'
], [
'type' => 'invalidpreference',
'value' => 'abcd'
]]
);
$context = context_system::instance();
@@ -503,6 +510,8 @@ class core_user_externallib_testcase extends externallib_advanced_testcase {
$this->assertEquals($dbuser->description, $user1['description']);
$this->assertEquals($dbuser->city, $user1['city']);
$this->assertEquals($dbuser->country, $user1['country']);
$this->assertEquals('atto', get_user_preferences('htmleditor', null, $dbuser));
$this->assertEquals(null, get_user_preferences('invalidpreference', null, $dbuser));
}
// Call without required capability
@@ -657,7 +666,14 @@ class core_user_externallib_testcase extends externallib_advanced_testcase {
'email' => 'usertest1@example.com',
'description' => 'This is a description for user 1',
'city' => 'Perth',
'country' => 'au'
'country' => 'au',
'preferences' => [[
'type' => 'htmleditor',
'value' => 'atto'
], [
'type' => 'invalidpreference',
'value' => 'abcd'
]]
);
$context = context_system::instance();
@@ -693,6 +709,8 @@ class core_user_externallib_testcase extends externallib_advanced_testcase {
$this->assertEquals($dbuser->description, $user1['description']);
$this->assertEquals($dbuser->city, $user1['city']);
$this->assertEquals($dbuser->country, $user1['country']);
$this->assertEquals('atto', get_user_preferences('htmleditor', null, $dbuser));
$this->assertEquals(null, get_user_preferences('invalidpreference', null, $dbuser));
// Call without required capability.
$this->unassignUserCapability('moodle/user:update', $context->id, $roleid);
+2 -2
View File
@@ -29,11 +29,11 @@
defined('MOODLE_INTERNAL') || die();
$version = 2014051218.00; // 20140512 = branching date YYYYMMDD - do not modify!
$version = 2014051220.00; // 20140512 = branching date YYYYMMDD - do not modify!
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '2.7.18 (Build: 20170109)'; // Human-friendly version name
$release = '2.7.20 (Build: 20170508)'; // Human-friendly version name
$branch = '27'; // This version's branch.
$maturity = MATURITY_STABLE; // This version's maturity level.