{{#competencies}}
-
+
{{#canmanagetemplatecompetencies}}
diff --git a/admin/tool/lp/templates/template_statistics.mustache b/admin/tool/lp/templates/template_statistics.mustache
index 9751cbd09ea04..418b4934b9e44 100644
--- a/admin/tool/lp/templates/template_statistics.mustache
+++ b/admin/tool/lp/templates/template_statistics.mustache
@@ -45,8 +45,7 @@
Template statistics template.
}}
{{#competencycount}}
-
-
+
{{< tool_lp/progress_bar}}
{{$progresstext}}
{{#str}}xcompetencieslinkedoutofy, tool_lp, { "x": "{{linkedcompetencycount}}", "y": "{{competencycount}}" } {{/str}}
@@ -90,6 +89,5 @@
{{/leastproficientcount}}
-
{{/competencycount}}
diff --git a/admin/tool/lp/templates/user_competency_course_navigation.mustache b/admin/tool/lp/templates/user_competency_course_navigation.mustache
index 331c3e15892ca..2a9f2deeda4c9 100644
--- a/admin/tool/lp/templates/user_competency_course_navigation.mustache
+++ b/admin/tool/lp/templates/user_competency_course_navigation.mustache
@@ -35,9 +35,12 @@
// No example context because the JS is connected to webservices
}}
-
{{#hasprogress}}
diff --git a/blocks/myoverview/templates/view-summary.mustache b/blocks/myoverview/templates/view-summary.mustache
index a57c69062517e..26bcdcc07d995 100644
--- a/blocks/myoverview/templates/view-summary.mustache
+++ b/blocks/myoverview/templates/view-summary.mustache
@@ -30,7 +30,8 @@
"summary": "This course is about assignments",
"hasprogress": true,
"progress": 10,
- "coursecategory": "Miscellaneous"
+ "coursecategory": "Miscellaneous",
+ "visible": true
}
]
}
@@ -75,6 +76,11 @@
{{> block_myoverview/course-action-menu }}
+ {{^visible}}
+
+ {{#str}} hiddenfromstudents {{/str}}
+
+ {{/visible}}
{{#str}}aria:coursesummary, block_myoverview{{/str}}
{{{summary}}}
diff --git a/blocks/myoverview/version.php b/blocks/myoverview/version.php
index bc9f98366748d..728053a0a0ab7 100644
--- a/blocks/myoverview/version.php
+++ b/blocks/myoverview/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2019052000; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->version = 2019052001; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2019051100; // Requires this Moodle version.
$plugin->component = 'block_myoverview'; // Full name of the plugin (used for diagnostics).
diff --git a/blocks/navigation/db/upgrade.php b/blocks/navigation/db/upgrade.php
index 97b106317ca71..1022e847e4c18 100644
--- a/blocks/navigation/db/upgrade.php
+++ b/blocks/navigation/db/upgrade.php
@@ -67,5 +67,8 @@ function xmldb_block_navigation_upgrade($oldversion, $block) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/blocks/quiz_results/db/upgrade.php b/blocks/quiz_results/db/upgrade.php
index 60b035ecaebaa..055bb61561f52 100644
--- a/blocks/quiz_results/db/upgrade.php
+++ b/blocks/quiz_results/db/upgrade.php
@@ -57,5 +57,8 @@ function xmldb_block_quiz_results_upgrade($oldversion, $block) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/blocks/recent_activity/db/upgrade.php b/blocks/recent_activity/db/upgrade.php
index 77e6f61c86165..1ad6e1aa1c982 100644
--- a/blocks/recent_activity/db/upgrade.php
+++ b/blocks/recent_activity/db/upgrade.php
@@ -59,5 +59,8 @@ function xmldb_block_recent_activity_upgrade($oldversion, $block) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/blocks/recentlyaccessedcourses/templates/course-card.mustache b/blocks/recentlyaccessedcourses/templates/course-card.mustache
index 7b98a5eb2034e..064935d87ae59 100644
--- a/blocks/recentlyaccessedcourses/templates/course-card.mustache
+++ b/blocks/recentlyaccessedcourses/templates/course-card.mustache
@@ -40,5 +40,8 @@
{{{coursecategory}}}
{{/coursecategory}}
+ {{$divider}}
+
|
+ {{/divider}}
{{$coursename}}
{{{fullname}}} {{/coursename}}
{{/ core_course/coursecard }}
diff --git a/blocks/recentlyaccesseditems/classes/helper.php b/blocks/recentlyaccesseditems/classes/helper.php
index b7d2b72af6f63..d1ac05b74baad 100644
--- a/blocks/recentlyaccesseditems/classes/helper.php
+++ b/blocks/recentlyaccesseditems/classes/helper.php
@@ -53,11 +53,13 @@ public static function get_recent_items(int $limit = 0) {
return $recentitems;
}
- // Determine sort sql clause.
- $sort = 'timeaccess DESC';
-
$paramsql = array('userid' => $userid);
- $records = $DB->get_records('block_recentlyaccesseditems', $paramsql, $sort);
+ $sql = "SELECT rai.*
+ FROM {block_recentlyaccesseditems} rai
+ JOIN {course} c ON c.id = rai.courseid
+ WHERE userid = :userid
+ ORDER BY rai.timeaccess DESC";
+ $records = $DB->get_records_sql($sql, $paramsql);
$order = 0;
// Get array of items by course. Use $order index to keep sql sorted results.
diff --git a/blocks/recentlyaccesseditems/db/upgrade.php b/blocks/recentlyaccesseditems/db/upgrade.php
new file mode 100644
index 0000000000000..8da5ad1eb00c7
--- /dev/null
+++ b/blocks/recentlyaccesseditems/db/upgrade.php
@@ -0,0 +1,73 @@
+.
+
+/**
+ * This file keeps track of upgrades to the recentlyaccesseditems block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @package block_recentlyaccesseditems
+ * @copyright 2019 Peter Dias
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Upgrade the recentlyaccesseditems db table.
+ *
+ * @param $oldversion
+ * @return bool
+ */
+function xmldb_block_recentlyaccesseditems_upgrade($oldversion, $block) {
+ global $DB;
+
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+ if ($oldversion < 2019052001) {
+ // Query the items to be deleted as a list of IDs. We cannot delete directly from this as a
+ // subquery because MySQL does not support delete with subqueries.
+ $fordeletion = $DB->get_fieldset_sql("
+ SELECT rai.id
+ FROM {block_recentlyaccesseditems} rai
+ LEFT JOIN {course} c ON c.id = rai.courseid
+ LEFT JOIN {course_modules} cm ON cm.id = rai.cmid
+ WHERE c.id IS NULL OR cm.id IS NULL");
+
+ // Delete the array in chunks of 500 (Oracle does not support more than 1000 parameters,
+ // let's leave some leeway, there are likely only one chunk anyway).
+ $chunks = array_chunk($fordeletion, 500);
+ foreach ($chunks as $chunk) {
+ $DB->delete_records_list('block_recentlyaccesseditems', 'id', $chunk);
+ }
+
+ upgrade_block_savepoint(true, 2019052001, 'recentlyaccesseditems', false);
+ }
+
+ return true;
+}
diff --git a/blocks/recentlyaccesseditems/lib.php b/blocks/recentlyaccesseditems/lib.php
new file mode 100644
index 0000000000000..eedf29d4b26fe
--- /dev/null
+++ b/blocks/recentlyaccesseditems/lib.php
@@ -0,0 +1,47 @@
+.
+
+/**
+ * The interface library between the core and the subsystem.
+ *
+ * @package block_recentlyaccesseditems
+ * @copyright 2019 Peter Dias
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Pre-delete course module hook to cleanup any records with references to the deleted module.
+ *
+ * @param stdClass $cm The deleted course module
+ */
+function block_recentlyaccesseditems_pre_course_module_delete($cm) {
+ global $DB;
+
+ $DB->delete_records('block_recentlyaccesseditems', ['cmid' => $cm->id]);
+}
+
+/**
+ * Pre-delete course hook to cleanup any records with references to the deleted course.
+ *
+ * @param stdClass $course The deleted course
+ */
+function block_recentlyaccesseditems_pre_course_delete($course) {
+ global $DB;
+
+ $DB->delete_records('block_recentlyaccesseditems', ['courseid' => $course->id]);
+}
diff --git a/blocks/recentlyaccesseditems/tests/externallib_test.php b/blocks/recentlyaccesseditems/tests/externallib_test.php
index 62de36a2340fb..b6d6b5e94396a 100644
--- a/blocks/recentlyaccesseditems/tests/externallib_test.php
+++ b/blocks/recentlyaccesseditems/tests/externallib_test.php
@@ -103,5 +103,15 @@ public function test_get_recent_items() {
}
$this->assertTrue($record->timeaccess < $result[$key - 1]->timeaccess);
}
+
+ // Delete a course and confirm it's activities don't get returned.
+ delete_course($courses[0], false);
+ $result = \block_recentlyaccesseditems\external::get_recent_items();
+ $this->assertCount((count($forum) + count($chat)) - 2, $result);
+
+ // Delete a single course module should still return.
+ course_delete_module($forum[1]->cmid);
+ $result = \block_recentlyaccesseditems\external::get_recent_items();
+ $this->assertCount((count($forum) + count($chat)) - 3, $result);
}
}
\ No newline at end of file
diff --git a/blocks/recentlyaccesseditems/tests/helper_test.php b/blocks/recentlyaccesseditems/tests/helper_test.php
new file mode 100644
index 0000000000000..aed88638bb044
--- /dev/null
+++ b/blocks/recentlyaccesseditems/tests/helper_test.php
@@ -0,0 +1,71 @@
+.
+
+/**
+ * Block recentlyaccesseditems helper tests.
+ *
+ * @package block_recentlyaccesseditems
+ * @copyright 2019 University of Nottingham
+ * @author Neill Magill
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+use block_recentlyaccesseditems\helper;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Block Recently accessed helper class tests.
+ *
+ * @package block_recentlyaccesseditems
+ * @copyright 2019 University of Nottingham
+ * @author Neill Magill
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_recentlyaccesseditems_helper_testcase extends advanced_testcase {
+ /**
+ * Tests that the get recent items method can handle getting records when courses have been deleted.
+ */
+ public function test_get_recent_items() {
+ $this->resetAfterTest();
+ $course = self::getDataGenerator()->create_course();
+ $coursetodelete = self::getDataGenerator()->create_course();
+ $user = self::getDataGenerator()->create_and_enrol($course, 'student');
+ self::getDataGenerator()->enrol_user($user->id, $coursetodelete->id, 'student');
+
+ // Add an activity to each course.
+ $forum = self::getDataGenerator()->create_module('forum', ['course' => $course]);
+ $glossary = self::getDataGenerator()->create_module('glossary', ['course' => $coursetodelete]);
+ self::setUser($user);
+
+ // Get the user to visit the activities.
+ $event1params = ['context' => context_module::instance($forum->cmid), 'objectid' => $forum->id];
+ $event1 = \mod_forum\event\course_module_viewed::create($event1params);
+ $event1->trigger();
+ $event2params = ['context' => context_module::instance($glossary->cmid), 'objectid' => $glossary->id];
+ $event2 = \mod_glossary\event\course_module_viewed::create($event2params);
+ $event2->trigger();
+ $recent1 = helper::get_recent_items();
+ self::assertCount(2, $recent1);
+ $recentlimited = helper::get_recent_items(1);
+ self::assertCount(1, $recentlimited);
+ delete_course($coursetodelete, false);
+
+ // There should be no errors if a course has been deleted.
+ $recent2 = helper::get_recent_items();
+ self::assertCount(1, $recent2);
+ }
+}
diff --git a/blocks/recentlyaccesseditems/tests/privacy_test.php b/blocks/recentlyaccesseditems/tests/privacy_test.php
index 8c5ab6957e487..92152c5605f2a 100644
--- a/blocks/recentlyaccesseditems/tests/privacy_test.php
+++ b/blocks/recentlyaccesseditems/tests/privacy_test.php
@@ -207,6 +207,60 @@ public function test_export_user_data() {
// Confirm student's data is exported.
$writer = \core_privacy\local\request\writer::with_context($studentcontext);
$this->assertTrue($writer->has_any_data());
+
+ delete_course($course, false);
+ $sc = context_user::instance($student->id);
+ $approvedlist = new approved_contextlist($student, $component, [$sc->id]);
+ provider::export_user_data($approvedlist);
+ $writer = \core_privacy\local\request\writer::with_context($sc);
+ $this->assertTrue($writer->has_any_data());
+ }
+
+ /**
+ * Test exporting data for an approved contextlist with a deleted course
+ */
+ public function test_export_user_data_with_deleted_course() {
+ global $DB;
+
+ $this->resetAfterTest();
+ $generator = $this->getDataGenerator();
+ $component = 'block_recentlyaccesseditems';
+
+ $student = $generator->create_user();
+ $studentcontext = context_user::instance($student->id);
+
+ // Enrol user in course and add course items.
+ $course = $generator->create_course();
+ $generator->enrol_user($student->id, $course->id, 'student');
+ $forum = $generator->create_module('forum', ['course' => $course]);
+ $chat = $generator->create_module('chat', ['course' => $course]);
+
+ // Generate some recent activity.
+ $this->setUser($student);
+ $event = \mod_forum\event\course_module_viewed::create(['context' => context_module::instance($forum->cmid),
+ 'objectid' => $forum->id]);
+ $event->trigger();
+ $event = \mod_chat\event\course_module_viewed::create(['context' => context_module::instance($chat->cmid),
+ 'objectid' => $chat->id]);
+ $event->trigger();
+
+ // Confirm data is present.
+ $params = [
+ 'courseid' => $course->id,
+ 'userid' => $student->id,
+ ];
+
+ $result = $DB->count_records('block_recentlyaccesseditems', $params);
+ $this->assertEquals(2, $result);
+ delete_course($course, false);
+
+ // Export data for student.
+ $approvedlist = new approved_contextlist($student, $component, [$studentcontext->id]);
+ provider::export_user_data($approvedlist);
+
+ // Confirm student's data is exported.
+ $writer = \core_privacy\local\request\writer::with_context($studentcontext);
+ $this->assertFalse($writer->has_any_data());
}
/**
diff --git a/blocks/recentlyaccesseditems/version.php b/blocks/recentlyaccesseditems/version.php
index c96794f089f7d..d60ba3c52febe 100644
--- a/blocks/recentlyaccesseditems/version.php
+++ b/blocks/recentlyaccesseditems/version.php
@@ -22,6 +22,6 @@
*/
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2019052000; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->version = 2019052001; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2019051100; // Requires this Moodle version.
$plugin->component = 'block_recentlyaccesseditems'; // Full name of the plugin (used for diagnostics).
diff --git a/blocks/rss_client/db/upgrade.php b/blocks/rss_client/db/upgrade.php
index 878f198c3f947..84dc47033e295 100644
--- a/blocks/rss_client/db/upgrade.php
+++ b/blocks/rss_client/db/upgrade.php
@@ -45,5 +45,8 @@ function xmldb_block_rss_client_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/blocks/rss_client/lang/en/block_rss_client.php b/blocks/rss_client/lang/en/block_rss_client.php
index afc0bab07b6c4..06facda0af264 100644
--- a/blocks/rss_client/lang/en/block_rss_client.php
+++ b/blocks/rss_client/lang/en/block_rss_client.php
@@ -43,7 +43,7 @@
$string['editnewsfeeds'] = 'Edit news feeds';
$string['editrssblock'] = 'Edit RSS headline block';
$string['enableautodiscovery'] = 'Enable auto-discovery of feeds?';
-$string['enableautodiscovery_help'] = 'If enabled, feeds on web pages are found automatically. For example, if http://docs.moodle.org is entered, then http://docs.moodle.org/en/index.php?title=Special:RecentChanges&feed=rss would be found.';
+$string['enableautodiscovery_help'] = 'If enabled, feeds on web pages are found automatically. For example, if https://docs.moodle.org is entered, then https://docs.moodle.org/en/index.php?title=Special:RecentChanges&feed=rss would be found.';
$string['failedfeed'] = 'Feed failed to download - will retry after {$a}';
$string['failedfeeds'] = 'One or more RSS feeds have failed';
$string['feed'] = 'Feed';
diff --git a/blocks/section_links/db/upgrade.php b/blocks/section_links/db/upgrade.php
index 0a8e2b0421b9c..41638f4753ba5 100644
--- a/blocks/section_links/db/upgrade.php
+++ b/blocks/section_links/db/upgrade.php
@@ -61,5 +61,8 @@ function xmldb_block_section_links_upgrade($oldversion, $block) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/blocks/selfcompletion/db/upgrade.php b/blocks/selfcompletion/db/upgrade.php
index 9b8d87bddb055..92b3268f797c0 100644
--- a/blocks/selfcompletion/db/upgrade.php
+++ b/blocks/selfcompletion/db/upgrade.php
@@ -60,5 +60,8 @@ function xmldb_block_selfcompletion_upgrade($oldversion, $block) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/blocks/settings/db/upgrade.php b/blocks/settings/db/upgrade.php
index 7b8618d76b6ad..f2b732712f1f6 100644
--- a/blocks/settings/db/upgrade.php
+++ b/blocks/settings/db/upgrade.php
@@ -67,5 +67,8 @@ function xmldb_block_settings_upgrade($oldversion, $block) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/blocks/site_main_menu/tests/behat/behat_block_site_main_menu.php b/blocks/site_main_menu/tests/behat/behat_block_site_main_menu.php
index f523116205902..b80713c60c69e 100644
--- a/blocks/site_main_menu/tests/behat/behat_block_site_main_menu.php
+++ b/blocks/site_main_menu/tests/behat/behat_block_site_main_menu.php
@@ -114,12 +114,8 @@ public function i_click_on_in_the_activity_in_site_main_menu_block($element, $se
protected function get_site_menu_activity_element($element, $selectortype, $activityname) {
$activitynode = $this->get_site_menu_activity_node($activityname);
- // Transforming to Behat selector/locator.
- list($selector, $locator) = $this->transform_selector($selectortype, $element);
- $exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' .
- $selectortype . '" in "' . $activityname . '" ');
-
- return $this->find($selector, $locator, $exception, $activitynode);
+ $exception = new ElementNotFoundException($this->getSession(), "'{$element}' '{$selectortype}' in '${activityname}'");
+ return $this->find($selectortype, $element, $exception, $activitynode);
}
/**
diff --git a/blocks/social_activities/tests/behat/behat_block_social_activities.php b/blocks/social_activities/tests/behat/behat_block_social_activities.php
index 2fe5526d473d8..167b24d51a2c0 100644
--- a/blocks/social_activities/tests/behat/behat_block_social_activities.php
+++ b/blocks/social_activities/tests/behat/behat_block_social_activities.php
@@ -56,7 +56,11 @@ protected function get_social_block_activity_node($activityname) {
}
/**
- * Checks that the specified activity's action menu contains an item.
+ * Checks that the specified activity in the social activities block should have the specified editing icon.
+ *
+ * This includes items in the action menu for the item (does not require it to be open)
+ *
+ * You should be in the course page with editing mode turned on.
*
* @Then /^"(?P(?:[^"]|\\")*)" activity in social activities block should have "(?P(?:[^"]|\\")*)" editing icon$/
* @param string $activityname
@@ -71,7 +75,11 @@ public function activity_in_social_activities_block_should_have_editing_icon($ac
}
/**
- * Checks that the specified activity's action menu contains an item.
+ * Checks that the specified activity in the social activities block should not have the specified editing icon.
+ *
+ * This includes items in the action menu for the item (does not require it to be open)
+ *
+ * You should be in the course page with editing mode turned on.
*
* @Then /^"(?P(?:[^"]|\\")*)" activity in social activities block should not have "(?P(?:[^"]|\\")*)" editing icon$/
* @param string $activityname
@@ -103,7 +111,7 @@ public function i_click_on_in_the_activity_in_social_activities_block($element,
}
/**
- * Clicks on the specified element inside the activity container.
+ * Finds the element containing a specific activity in the social activity block.
*
* @throws ElementNotFoundException
* @param string $element
@@ -114,16 +122,12 @@ public function i_click_on_in_the_activity_in_social_activities_block($element,
protected function get_social_block_activity_element($element, $selectortype, $activityname) {
$activitynode = $this->get_social_block_activity_node($activityname);
- // Transforming to Behat selector/locator.
- list($selector, $locator) = $this->transform_selector($selectortype, $element);
- $exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' .
- $selectortype . '" in "' . $activityname . '" ');
-
- return $this->find($selector, $locator, $exception, $activitynode);
+ $exception = new ElementNotFoundException($this->getSession(), "'{$element}' '{$selectortype}' in '${activityname}'");
+ return $this->find($selectortype, $element, $exception, $activitynode);
}
/**
- * Checks that the specified activity is hidden.
+ * Checks that the specified activity is hidden in the social activities block.
*
* @Then /^"(?P(?:[^"]|\\")*)" activity in social activities block should be hidden$/
* @param string $activityname
@@ -133,7 +137,7 @@ public function activity_in_social_activities_block_should_be_hidden($activityna
}
/**
- * Checks that the specified activity is hidden.
+ * Checks that the specified activity is hidden in the social activities block.
*
* @Then /^"(?P(?:[^"]|\\")*)" activity in social activities block should be available but hidden from course page$/
* @param string $activityname
@@ -143,7 +147,7 @@ public function activity_in_social_activities_block_should_be_available_but_hidd
}
/**
- * Opens an activity actions menu if it is not already opened.
+ * Opens an activity actions menu in the social activities block if it is not already opened.
*
* @Given /^I open "(?P(?:[^"]|\\")*)" actions menu in social activities block$/
* @throws DriverException The step is not available when Javascript is disabled
diff --git a/blocks/starredcourses/classes/external.php b/blocks/starredcourses/classes/external.php
index f5cb1c2c04d17..d1ace2cd0f3fd 100644
--- a/blocks/starredcourses/classes/external.php
+++ b/blocks/starredcourses/classes/external.php
@@ -88,13 +88,18 @@ public static function get_starred_courses($limit, $offset) {
return ($a->timemodified > $b->timemodified) ? -1 : 1;
});
- $formattedcourses = array_map(function($favourite) use ($renderer) {
+ $formattedcourses = array();
+ foreach ($favourites as $favourite) {
$course = get_course($favourite->itemid);
$context = \context_course::instance($favourite->itemid);
-
- $exporter = new course_summary_exporter($course, ['context' => $context, 'isfavourite' => true]);
- return $exporter->export($renderer);
- }, $favourites);
+ $canviewhiddencourses = has_capability('moodle/course:viewhiddencourses', $context);
+
+ if ($course->visible || $canviewhiddencourses) {
+ $exporter = new course_summary_exporter($course, ['context' => $context, 'isfavourite' => true]);
+ $formattedcourse = $exporter->export($renderer);
+ $formattedcourses[] = $formattedcourse;
+ }
+ }
return $formattedcourses;
}
diff --git a/blocks/timeline/amd/build/event_list.min.js b/blocks/timeline/amd/build/event_list.min.js
index 893a2ac780254..43ae0c6fea054 100644
--- a/blocks/timeline/amd/build/event_list.min.js
+++ b/blocks/timeline/amd/build/event_list.min.js
@@ -1 +1 @@
-define(["jquery","core/notification","core/templates","core/paged_content_factory","core/str","core/user_date","block_timeline/calendar_events_repository"],function(a,b,c,d,e,f,g){var h=86400,i={EMPTY_MESSAGE:'[data-region="empty-message"]',ROOT:'[data-region="event-list-container"]',EVENT_LIST_CONTENT:'[data-region="event-list-content"]',EVENT_LIST_LOADING_PLACEHOLDER:'[data-region="event-list-loading-placeholder"]'},j={EVENT_LIST_CONTENT:"block_timeline/event-list-content"},k={ignoreControlWhileLoading:!0,controlPlacementBottom:!0,ariaLabels:{itemsperpagecomponents:"ariaeventlistpagelimit, block_timeline"}},l=function(a){a.find(i.EVENT_LIST_CONTENT).addClass("hidden"),a.find(i.EMPTY_MESSAGE).removeClass("hidden")},m=function(a){a.find(i.EVENT_LIST_CONTENT).removeClass("hidden"),a.find(i.EMPTY_MESSAGE).addClass("hidden")},n=function(a){a.find(i.EVENT_LIST_CONTENT).empty()},o=function(a,b){var c={},d={eventsbyday:[]};return a.forEach(function(a){var d=f.getUserMidnightForTimestamp(a.timesort,b);c[d]?c[d].push(a):c[d]=[a]}),Object.keys(c).forEach(function(a){var e=c[a];d.eventsbyday.push({past:ac}return!0}),e=d.length<=k;return e?b.allItemsLoaded(j):d.pop(),d})},s=function(c,f,g,h,i,j,l,m,n){var o={1:0},q=!1,s=a.extend({},k,n);return e.get_string("ariaeventlistpagelimit","block_timeline",a.isArray(c)?c[0].value:c).then(function(a){return s.ariaLabels.itemsperpage=a,s.ariaLabels.paginationnav=m,a}).then(function(){return d.createWithLimit(c,function(c,d){var e=[];return c.forEach(function(a){var c=a.pageNumber,h=r(a,d,g,o,f,i,j,l).then(function(a){if(a.length){q=!0;var b=a[a.length-1].id;return o[c+1]=b,p(a,g)}return a})["catch"](b.exception);e.push(h)}),a.when.apply(a,e).then(function(){h.resolve(q)})["catch"](function(){h.resolve(q)}),e},s)})},t=function(d,e,f,g,h){d=a(d);var j=a.Deferred(),k=d.find(i.EVENT_LIST_CONTENT),o=d.find(i.EVENT_LIST_LOADING_PLACEHOLDER),p=d.attr("data-course-id"),q=parseInt(d.attr("data-days-offset"),10),r=d.attr("data-days-limit"),t=parseInt(d.attr("data-midnight"),10);return n(d),m(d),o.removeClass("hidden"),void 0!=r&&(r=parseInt(r,10)),s(e,f,t,j,p,q,r,g,h).then(function(b,e){return b=a(b),b.addClass("hidden"),c.replaceNodeContents(k,b,e),j.then(function(a){return b.removeClass("hidden"),o.addClass("hidden"),a||l(d),a})["catch"](function(){return!1}),b})["catch"](b.exception)};return{init:t,rootSelector:i.ROOT}});
\ No newline at end of file
diff --git a/blocks/timeline/amd/src/event_list.js b/blocks/timeline/amd/src/event_list.js
index 9699ed1c68f20..c7c504e107ac0 100644
--- a/blocks/timeline/amd/src/event_list.js
+++ b/blocks/timeline/amd/src/event_list.js
@@ -265,7 +265,13 @@ function(
return [];
}
- var calendarEvents = result.events;
+ var calendarEvents = result.events.filter(function(event) {
+ if (event.eventtype == "open" || event.eventtype == "opensubmission") {
+ var dayTimestamp = UserDate.getUserMidnightForTimestamp(event.timesort, midnight);
+ return dayTimestamp > midnight;
+ }
+ return true;
+ });
// We expect to receive limit + 1 events back from the server.
// Any less means there are no more events to load.
var loadedAll = calendarEvents.length <= limit;
diff --git a/blocks/timeline/templates/event-list-content.mustache b/blocks/timeline/templates/event-list-content.mustache
index b8df729d6d86a..f138e9c57ca42 100644
--- a/blocks/timeline/templates/event-list-content.mustache
+++ b/blocks/timeline/templates/event-list-content.mustache
@@ -65,7 +65,7 @@
}}
{{#eventsbyday}}
-
{{#userdate}} {{dayTimestamp}}, {{#str}} strftimedayshort, core_langconfig {{/str}} {{/userdate}}
+ {{#userdate}} {{dayTimestamp}}, {{#str}} strftimedaydate, core_langconfig {{/str}} {{/userdate}}
{{> block_timeline/event-list-items }}
{{/eventsbyday}}
\ No newline at end of file
diff --git a/blocks/timeline/templates/event-list-item.mustache b/blocks/timeline/templates/event-list-item.mustache
index b89e8083160d2..dc98508dcf305 100644
--- a/blocks/timeline/templates/event-list-item.mustache
+++ b/blocks/timeline/templates/event-list-item.mustache
@@ -50,13 +50,16 @@
{{{name}}}
-
{{{course.fullnamedisplay}}}
+ title={{#quote}}{{{name}}}{{/quote}}
+ aria-label='{{#str}} ariaeventlistitem, block_timeline, { "name": {{#quote}}{{{name}}}{{/quote}}, "course": {{#quote}}{{{course.fullnamedisplay}}}{{/quote}}, "date": "{{#userdate}} {{timesort}}, {{#str}} strftimedatetime, core_langconfig {{/str}} {{/userdate}}" } {{/str}}'
+ >
{{#quote}}{{{name}}}{{/quote}}
+
{{#quote}}{{{course.fullnamedisplay}}}{{/quote}}
{{#action.actionable}}
{{{action.name}}}
+ {{#action.showitemcount}}
+ {{action.itemcount}}
+ {{/action.showitemcount}}
{{/action.actionable}}
diff --git a/blog/classes/privacy/provider.php b/blog/classes/privacy/provider.php
index 4bbc744a1db4d..8ff19c3f03dee 100644
--- a/blog/classes/privacy/provider.php
+++ b/blog/classes/privacy/provider.php
@@ -460,8 +460,7 @@ public static function delete_data_for_user(approved_contextlist $contextlist) {
$params = array_merge($inparams, ['userid' => $userid]);
$associds = $DB->get_fieldset_sql($sql, $params);
- list($insql, $inparams) = $DB->get_in_or_equal($associds, SQL_PARAMS_NAMED, 'param', true);
- $DB->delete_records_select('blog_association', "id $insql", $inparams);
+ $DB->delete_records_list('blog_association', 'id', $associds);
}
}
diff --git a/blog/rsslib.php b/blog/rsslib.php
index d671d1b52f9ba..37d1968e7026d 100644
--- a/blog/rsslib.php
+++ b/blog/rsslib.php
@@ -83,7 +83,7 @@ function blog_rss_print_link($context, $filtertype, $filterselect = 0, $tagid =
$url = blog_rss_get_url($context->id, $userid, $filtertype, $filterselect, $tagid);
$rsspix = $OUTPUT->pix_icon('i/rss', get_string('rss'), 'core', array('title' => $tooltiptext));
- print '
';
+ print '
';
}
/**
diff --git a/blog/tests/privacy_test.php b/blog/tests/privacy_test.php
index 8db5bdd6bd454..700255291da39 100644
--- a/blog/tests/privacy_test.php
+++ b/blog/tests/privacy_test.php
@@ -370,6 +370,37 @@ public function test_delete_data_for_user() {
$this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
}
+ /**
+ * Test provider delete_data_for_user with a context that contains no entries
+ *
+ * @return void
+ */
+ public function test_delete_data_for_user_empty_context() {
+ global $DB;
+
+ $user = $this->getDataGenerator()->create_user();
+ $course = $this->getDataGenerator()->create_course();
+ $context = context_course::instance($course->id);
+
+ // Create a blog entry for user, associated with course.
+ $entry = new blog_entry($this->create_post(['userid' => $user->id, 'courseid' => $course->id])->id);
+ $entry->add_association($context->id);
+
+ // Generate list of contexts for user.
+ $contexts = provider::get_contexts_for_userid($user->id);
+ $this->assertContains($context->id, $contexts->get_contextids());
+
+ // Now delete the blog entry.
+ $entry->delete();
+
+ // Try to delete user data using contexts obtained prior to entry deletion.
+ $contextlist = new approved_contextlist($user, 'core_blog', $contexts->get_contextids());
+ provider::delete_data_for_user($contextlist);
+
+ // Sanity check to ensure blog_associations is really empty.
+ $this->assertEmpty($DB->get_records('blog_association', ['contextid' => $context->id]));
+ }
+
public function test_delete_data_for_all_users_in_context() {
global $DB;
diff --git a/cache/stores/mongodb/MongoDB/LICENSE b/cache/stores/mongodb/MongoDB/LICENSE
new file mode 100644
index 0000000000000..d645695673349
--- /dev/null
+++ b/cache/stores/mongodb/MongoDB/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/cache/stores/mongodb/MongoDB/readme_moodle.txt b/cache/stores/mongodb/MongoDB/readme_moodle.txt
index 456d3fde16492..da6ad07859014 100644
--- a/cache/stores/mongodb/MongoDB/readme_moodle.txt
+++ b/cache/stores/mongodb/MongoDB/readme_moodle.txt
@@ -1,14 +1,15 @@
MongoDB PHP
-----------
-
-Downloaded from https://github.com/mongodb/mongo-php-library
-
-Last commit on download: aac8e54009196f6544e50baf9b63dcf0eab3bbdf
-
-This version (1.4) requires PHP mongodb extension >= 1.5
+Download from https://github.com/mongodb/mongo-php-library
Import procedure:
- Copy all the files and folders from the folder mongodb/src in this directory.
- Copy the license file from the project root.
+- Update thirdpartylibs.xml with the latest version.
+
+2019/03/14
+----------
+Last commit on download: aac8e54009196f6544e50baf9b63dcf0eab3bbdf
+This version (1.4.2) requires PHP mongodb extension >= 1.5
diff --git a/cache/stores/mongodb/thirdpartylibs.xml b/cache/stores/mongodb/thirdpartylibs.xml
index bd22d79e9353d..afc8de0e7c483 100644
--- a/cache/stores/mongodb/thirdpartylibs.xml
+++ b/cache/stores/mongodb/thirdpartylibs.xml
@@ -4,7 +4,7 @@
MongoDB
MongoDB PHP Library
Apache
-
1.4
+
1.4.2
2.0
\ No newline at end of file
diff --git a/cache/stores/redis/lib.php b/cache/stores/redis/lib.php
index 83a58892e5bfd..35962002b95ca 100644
--- a/cache/stores/redis/lib.php
+++ b/cache/stores/redis/lib.php
@@ -150,7 +150,8 @@ public function __construct($name, array $configuration = array()) {
*/
protected function new_redis($server, $prefix = '', $password = '') {
$redis = new Redis();
- $port = null;
+ // Check if it isn't a Unix socket to set default port.
+ $port = ($server[0] === '/') ? null : 6379;
if (strpos($server, ':')) {
$serverconf = explode(':', $server);
$server = $serverconf[0];
diff --git a/calendar/amd/build/calendar_filter.min.js b/calendar/amd/build/calendar_filter.min.js
index ddf2010dcef1d..9ce9df0c1b6ab 100644
--- a/calendar/amd/build/calendar_filter.min.js
+++ b/calendar/amd/build/calendar_filter.min.js
@@ -1 +1 @@
-define(["jquery","core_calendar/selectors","core_calendar/events","core/str","core/templates"],function(a,b,c,d,e){var f=function(d){d.on("click",b.eventFilterItem,function(b){var c=a(b.currentTarget);g(c),b.preventDefault()}),a("body").on(c.viewUpdated,function(){var c=d.find(b.eventFilterItem);c.each(function(b,c){if(c=a(c),c.data("eventtype-hidden")){var d=i(c);h(d)}})})},g=function(a){var b=i(a);return b.hidden=!b.hidden,d.get_string("eventtype"+b.eventtype,"calendar").then(function(a){return b.name=a,b}).then(function(a){return e.render("core_calendar/event_filter_key",a)}).then(function(b,c){return e.replaceNode(a,b,c)}).then(function(){h(b)})},h=function(b){M.util.js_pending("month-mini-filterChanged"),a("body").trigger(c.filterChanged,{type:b.eventtype,hidden:b.hidden}),M.util.js_complete("month-mini-filterChanged")},i=function(a){return{eventtype:a.data("eventtype"),hidden:a.data("eventtype-hidden")}};return{init:function(b){b=a(b),f(b)}}});
\ No newline at end of file
+define(["jquery","core_calendar/selectors","core_calendar/events","core/str","core/templates"],function(a,b,c,d,e){var f=function(d){d.on("click",b.eventFilterItem,function(b){var c=a(b.currentTarget);g(c),b.preventDefault()}),a("body").on(c.viewUpdated,function(){var c=d.find(b.eventFilterItem);c.each(function(b,c){if(c=a(c),c.data("eventtype-hidden")){var d=i(c);h(d)}})})},g=function(a){var b=i(a);return b.hidden=!b.hidden,d.get_string("eventtype"+b.eventtype,"calendar").then(function(a){return b.name=a,b.icon=!0,b.key="i/"+b.eventtype+"event",b.component="core",b}).then(function(a){return e.render("core_calendar/event_filter_key",a)}).then(function(b,c){return e.replaceNode(a,b,c)}).then(function(){h(b)})},h=function(b){M.util.js_pending("month-mini-filterChanged"),a("body").trigger(c.filterChanged,{type:b.eventtype,hidden:b.hidden}),M.util.js_complete("month-mini-filterChanged")},i=function(a){return{eventtype:a.data("eventtype"),hidden:a.data("eventtype-hidden")}};return{init:function(b){b=a(b),f(b)}}});
\ No newline at end of file
diff --git a/calendar/amd/src/calendar_filter.js b/calendar/amd/src/calendar_filter.js
index 622dafd890c79..41dd4488e8b65 100644
--- a/calendar/amd/src/calendar_filter.js
+++ b/calendar/amd/src/calendar_filter.js
@@ -67,6 +67,9 @@ function(
return Str.get_string('eventtype' + data.eventtype, 'calendar')
.then(function(nameStr) {
data.name = nameStr;
+ data.icon = true;
+ data.key = 'i/' + data.eventtype + 'event';
+ data.component = 'core';
return data;
})
diff --git a/calendar/classes/external/event_exporter_base.php b/calendar/classes/external/event_exporter_base.php
index 08d14acf101b2..f761f705bcdc6 100644
--- a/calendar/classes/external/event_exporter_base.php
+++ b/calendar/classes/external/event_exporter_base.php
@@ -275,7 +275,9 @@ protected function get_other_values(renderer_base $output) {
}
$timesort = $event->get_times()->get_sort_time()->getTimestamp();
$iconexporter = new event_icon_exporter($event, ['context' => $context]);
- $values['normalisedeventtypetext'] = get_string('type' . $values['normalisedeventtype'], 'calendar');
+ $identifier = 'type' . $values['normalisedeventtype'];
+ $stringexists = get_string_manager()->string_exists($identifier, 'calendar');
+ $values['normalisedeventtypetext'] = $stringexists ? get_string($identifier, 'calendar') : '';
$values['icon'] = $iconexporter->export($output);
diff --git a/calendar/classes/external/footer_options_exporter.php b/calendar/classes/external/footer_options_exporter.php
index 5d7f198fecbfe..da7b69de58538 100644
--- a/calendar/classes/external/footer_options_exporter.php
+++ b/calendar/classes/external/footer_options_exporter.php
@@ -100,8 +100,6 @@ protected function get_link_params() {
$params['course'] = $this->calendar->course->id;
} else if (null !== $this->calendar->categoryid && $this->calendar->categoryid > 0) {
$params['category'] = $this->calendar->categoryid;
- } else {
- $params['course'] = SITEID;
}
return $params;
diff --git a/calendar/classes/local/event/data_access/event_vault.php b/calendar/classes/local/event/data_access/event_vault.php
index 3d592088d58b1..8a8c20d2f3bb7 100644
--- a/calendar/classes/local/event/data_access/event_vault.php
+++ b/calendar/classes/local/event/data_access/event_vault.php
@@ -100,9 +100,6 @@ public function get_events(
$ignorehidden = true,
callable $filter = null
) {
- if ($limitnum < 1 || $limitnum > 200) {
- throw new limit_invalid_parameter_exception("Limit must be between 1 and 200 (inclusive)");
- }
$fromquery = function($field, $timefrom, $lastseenmethod, $afterevent, $withduration) {
if (!$timefrom) {
@@ -186,7 +183,11 @@ public function get_events(
}
}
- $offset += $limitnum;
+ if (!$limitnum) {
+ break;
+ } else {
+ $offset += $limitnum;
+ }
}
return $events;
diff --git a/calendar/classes/local/event/factories/event_abstract_factory.php b/calendar/classes/local/event/factories/event_abstract_factory.php
index ff697dd581794..b810ff8b5f747 100644
--- a/calendar/classes/local/event/factories/event_abstract_factory.php
+++ b/calendar/classes/local/event/factories/event_abstract_factory.php
@@ -138,7 +138,9 @@ public function create_instance(\stdClass $dbrow) {
$module = new cm_info_proxy($dbrow->modulename, $dbrow->instance, $dbrow->courseid);
}
- $category = new coursecat_proxy($dbrow->categoryid);
+ if ($dbrow->categoryid) {
+ $category = new coursecat_proxy($dbrow->categoryid);
+ }
$course = new std_proxy($dbrow->courseid, function($id) {
return calendar_get_course_cached($this->coursecachereference, $id);
diff --git a/calendar/classes/local/event/forms/eventtype.php b/calendar/classes/local/event/forms/eventtype.php
index b3d582694f12b..d615a50804ba7 100644
--- a/calendar/classes/local/event/forms/eventtype.php
+++ b/calendar/classes/local/event/forms/eventtype.php
@@ -98,7 +98,7 @@ protected function add_event_type_elements($mform, $eventtypes) {
$mform->hideIf('categoryid', 'eventtype', 'noteq', 'category');
}
- $showall = $CFG->calendar_adminseesall && !has_capability('moodle/calendar:manageentries', \context_system::instance());
+ $showall = is_siteadmin() && !empty($CFG->calendar_adminseesall);
if (!empty($eventtypes['course'])) {
$mform->addElement('course', 'courseid', get_string('course'), ['limittoenrolled' => !$showall]);
$mform->hideIf('courseid', 'eventtype', 'noteq', 'course');
diff --git a/calendar/classes/local/event/mappers/create_update_form_mapper.php b/calendar/classes/local/event/mappers/create_update_form_mapper.php
index 032d83930b107..e4ef1e80c771a 100644
--- a/calendar/classes/local/event/mappers/create_update_form_mapper.php
+++ b/calendar/classes/local/event/mappers/create_update_form_mapper.php
@@ -70,11 +70,13 @@ public function from_legacy_event_to_data(\calendar_event $legacyevent) {
'format' => $data->format
];
- // We don't want to return the context because it's not a
- // form value and breaks the validation.
+ // Don't return context or subscription because they're not form values and break validation.
if (isset($data->context)) {
unset($data->context);
}
+ if (isset($data->subscription)) {
+ unset($data->subscription);
+ }
return $data;
}
diff --git a/calendar/classes/local/event/mappers/event_mapper.php b/calendar/classes/local/event/mappers/event_mapper.php
index 5600ec76bcaf7..dc2ef2cb41696 100644
--- a/calendar/classes/local/event/mappers/event_mapper.php
+++ b/calendar/classes/local/event/mappers/event_mapper.php
@@ -95,6 +95,7 @@ public function from_event_to_legacy_event(event_interface $event) {
// Normalise for the legacy event because it wants zero rather than null.
$properties->courseid = empty($properties->courseid) ? 0 : $properties->courseid;
+ $properties->categoryid = empty($properties->categoryid) ? 0 : $properties->categoryid;
$properties->groupid = empty($properties->groupid) ? 0 : $properties->groupid;
$properties->userid = empty($properties->userid) ? 0 : $properties->userid;
$properties->modulename = empty($properties->modulename) ? 0 : $properties->modulename;
diff --git a/calendar/export_execute.php b/calendar/export_execute.php
index f87e439e632ff..17b55010e8e6a 100644
--- a/calendar/export_execute.php
+++ b/calendar/export_execute.php
@@ -186,9 +186,9 @@
die();
}
}
-
+$limitnum = 0;
$events = calendar_get_legacy_events($timestart, $timeend, $users, $groups, array_keys($paramcourses), false, true,
- $paramcategory);
+ $paramcategory, $limitnum);
$ical = new iCalendar;
$ical->add_property('method', 'PUBLISH');
diff --git a/calendar/externallib.php b/calendar/externallib.php
index 8d4a3a9398427..c61202a7aec85 100644
--- a/calendar/externallib.php
+++ b/calendar/externallib.php
@@ -676,7 +676,7 @@ public static function create_calendar_events_parameters() {
}
/**
- * Delete Calendar events.
+ * Create calendar events.
*
* @param array $events A list of events to create.
* @return array array of events created.
@@ -870,6 +870,11 @@ public static function submit_create_update_form($formdata) {
self::validate_context($context);
parse_str($params['formdata'], $data);
+ if (WS_SERVER) {
+ // Request via WS, ignore sesskey checks in form library.
+ $USER->ignoresesskey = true;
+ }
+
$eventtype = isset($data['eventtype']) ? $data['eventtype'] : null;
$coursekey = ($eventtype == 'group') ? 'groupcourseid' : 'courseid';
$courseid = (!empty($data[$coursekey])) ? $data[$coursekey] : null;
@@ -1021,8 +1026,8 @@ public static function get_calendar_monthly_view($year, $month, $courseid, $cate
public static function get_calendar_monthly_view_parameters() {
return new external_function_parameters(
[
- 'year' => new external_value(PARAM_INT, 'Month to be viewed', VALUE_REQUIRED),
- 'month' => new external_value(PARAM_INT, 'Year to be viewed', VALUE_REQUIRED),
+ 'year' => new external_value(PARAM_INT, 'Year to be viewed', VALUE_REQUIRED),
+ 'month' => new external_value(PARAM_INT, 'Month to be viewed', VALUE_REQUIRED),
'courseid' => new external_value(PARAM_INT, 'Course being viewed', VALUE_DEFAULT, SITEID, NULL_ALLOWED),
'categoryid' => new external_value(PARAM_INT, 'Category being viewed', VALUE_DEFAULT, null, NULL_ALLOWED),
'includenavigation' => new external_value(
diff --git a/calendar/lib.php b/calendar/lib.php
index 02c2d971392f5..a9df414b51d15 100644
--- a/calendar/lib.php
+++ b/calendar/lib.php
@@ -104,6 +104,11 @@
*/
define('CALENDAR_IMPORT_FROM_URL', 1);
+/**
+ * CALENDAR_IMPORT_EVENT_UPDATED_SKIPPED - imported event was skipped
+ */
+define('CALENDAR_IMPORT_EVENT_SKIPPED', -1);
+
/**
* CALENDAR_IMPORT_EVENT_UPDATED - imported event was updated
*/
@@ -2198,8 +2203,8 @@ function calendar_view_event_allowed(calendar_event $event) {
if (has_capability('moodle/calendar:manageentries', $event->context)) {
return true;
}
- $mycourses = enrol_get_my_courses('id');
- return isset($mycourses[$event->courseid]);
+
+ return can_access_course(get_course($event->courseid));
} else if ($event->userid) {
if ($event->userid != $USER->id) {
// No-one can ever see another users events.
@@ -2865,11 +2870,23 @@ function calendar_add_icalendar_event($event, $unused = null, $subscriptionid, $
if ($updaterecord = $DB->get_record('event', array('uuid' => $eventrecord->uuid,
'subscriptionid' => $eventrecord->subscriptionid))) {
- $eventrecord->id = $updaterecord->id;
- $return = CALENDAR_IMPORT_EVENT_UPDATED; // Update.
+
+ // Compare iCal event data against the moodle event to see if something has changed.
+ $result = array_diff((array) $eventrecord, (array) $updaterecord);
+
+ // Unset timemodified field because it's always going to be different.
+ unset($result['timemodified']);
+
+ if (count($result)) {
+ $eventrecord->id = $updaterecord->id;
+ $return = CALENDAR_IMPORT_EVENT_UPDATED; // Update.
+ } else {
+ return CALENDAR_IMPORT_EVENT_SKIPPED;
+ }
} else {
$return = CALENDAR_IMPORT_EVENT_INSERTED; // Insert.
}
+
if ($createdevent = \calendar_event::create($eventrecord, false)) {
if (!empty($event->properties['RRULE'])) {
// Repeating events.
@@ -2993,7 +3010,7 @@ function calendar_get_icalendar($url) {
* Import events from an iCalendar object into a course calendar.
*
* @param iCalendar $ical The iCalendar object.
- * @param int $courseid The course ID for the calendar.
+ * @param int $unused Deprecated
* @param int $subscriptionid The subscription ID.
* @return string A log of the import progress, including errors.
*/
@@ -3003,18 +3020,13 @@ function calendar_import_icalendar_events($ical, $unused = null, $subscriptionid
$return = '';
$eventcount = 0;
$updatecount = 0;
+ $skippedcount = 0;
// Large calendars take a while...
if (!CLI_SCRIPT) {
\core_php_time_limit::raise(300);
}
- // Mark all events in a subscription with a zero timestamp.
- if (!empty($subscriptionid)) {
- $sql = "UPDATE {event} SET timemodified = :time WHERE subscriptionid = :id";
- $DB->execute($sql, array('time' => 0, 'id' => $subscriptionid));
- }
-
// Grab the timezone from the iCalendar file to be used later.
if (isset($ical->properties['X-WR-TIMEZONE'][0]->value)) {
$timezone = $ical->properties['X-WR-TIMEZONE'][0]->value;
@@ -3022,8 +3034,9 @@ function calendar_import_icalendar_events($ical, $unused = null, $subscriptionid
$timezone = 'UTC';
}
- $return = '';
+ $icaluuids = [];
foreach ($ical->components['VEVENT'] as $event) {
+ $icaluuids[] = $event->properties['UID'][0]->value;
$res = calendar_add_icalendar_event($event, null, $subscriptionid, $timezone);
switch ($res) {
case CALENDAR_IMPORT_EVENT_UPDATED:
@@ -3032,6 +3045,9 @@ function calendar_import_icalendar_events($ical, $unused = null, $subscriptionid
case CALENDAR_IMPORT_EVENT_INSERTED:
$eventcount++;
break;
+ case CALENDAR_IMPORT_EVENT_SKIPPED:
+ $skippedcount++;
+ break;
case 0:
$return .= '
' . get_string('erroraddingevent', 'calendar') . ': ';
if (empty($event->properties['SUMMARY'])) {
@@ -3044,18 +3060,28 @@ function calendar_import_icalendar_events($ical, $unused = null, $subscriptionid
}
}
- $return .= "
" . get_string('eventsimported', 'calendar', $eventcount) . "
";
- $return .= "
" . get_string('eventsupdated', 'calendar', $updatecount) . "
";
+ $existing = $DB->get_field('event_subscriptions', 'lastupdated', ['id' => $subscriptionid]);
+ if (!empty($existing)) {
+ $eventsuuids = $DB->get_records_menu('event', ['subscriptionid' => $subscriptionid], '', 'id, uuid');
- // Delete remaining zero-marked events since they're not in remote calendar.
- if (!empty($subscriptionid)) {
- $deletecount = $DB->count_records('event', array('timemodified' => 0, 'subscriptionid' => $subscriptionid));
- if (!empty($deletecount)) {
- $DB->delete_records('event', array('timemodified' => 0, 'subscriptionid' => $subscriptionid));
- $return .= "
" . get_string('eventsdeleted', 'calendar') . ": {$deletecount}
\n";
+ $icaleventscount = count($icaluuids);
+ $tobedeleted = [];
+ if (count($eventsuuids) > $icaleventscount) {
+ foreach ($eventsuuids as $eventid => $eventuuid) {
+ if (!in_array($eventuuid, $icaluuids)) {
+ $tobedeleted[] = $eventid;
+ }
+ }
+ if (!empty($tobedeleted)) {
+ $DB->delete_records_list('event', 'id', $tobedeleted);
+ $return .= "
" . get_string('eventsdeleted', 'calendar') . ": " . count($tobedeleted) . "
";
+ }
}
}
+ $return .= "
" . get_string('eventsimported', 'calendar', $eventcount) . "
";
+ $return .= "
" . get_string('eventsskipped', 'calendar', $skippedcount) . "
";
+ $return .= "
" . get_string('eventsupdated', 'calendar', $updatecount) . "
";
return $return;
}
@@ -3237,10 +3263,12 @@ function core_calendar_user_preferences() {
* or events in progress/already started selected as well
* @param boolean $ignorehidden whether to select only visible events or all events
* @param array $categories array of category ids and/or objects.
+ * @param int $limitnum Number of events to fetch or zero to fetch all.
+ *
* @return array $events of selected events or an empty array if there aren't any (or there was an error)
*/
function calendar_get_legacy_events($tstart, $tend, $users, $groups, $courses,
- $withduration = true, $ignorehidden = true, $categories = []) {
+ $withduration = true, $ignorehidden = true, $categories = [], $limitnum = 0) {
// Normalise the users, groups and courses parameters so that they are compliant with \core_calendar\local\api::get_events().
// Existing functions that were using the old calendar_get_events() were passing a mixture of array, int, boolean for these
// parameters, but with the new API method, only null and arrays are accepted.
@@ -3277,7 +3305,7 @@ function calendar_get_legacy_events($tstart, $tend, $users, $groups, $courses,
null,
null,
null,
- 40,
+ $limitnum,
null,
$userparam,
$groupparam,
@@ -3314,7 +3342,7 @@ function calendar_get_view(\calendar_information $calendar, $view, $includenavig
$calendardate = $type->timestamp_to_date_array($calendar->time);
$date = new \DateTime('now', core_date::get_user_timezone_object(99));
- $eventlimit = 200;
+ $eventlimit = 0;
if ($view === 'day') {
$tstart = $type->convert_to_timestamp($calendardate['year'], $calendardate['mon'], $calendardate['mday']);
@@ -3500,7 +3528,7 @@ function calendar_output_fragment_event_form($args) {
$eventtypes = calendar_get_allowed_event_types($courseid);
// If the user is on course context and is allowed to add course events set the event type default to course.
- if ($courseid != SITEID && !empty($eventtypes['course'])) {
+ if (!empty($courseid) && !empty($eventtypes['course'])) {
$data['eventtype'] = 'course';
$data['courseid'] = $courseid;
$data['groupcourseid'] = $courseid;
@@ -3641,6 +3669,9 @@ function calendar_get_filter_types() {
return [
'eventtype' => $type,
'name' => get_string("eventtype{$type}", "calendar"),
+ 'icon' => true,
+ 'key' => 'i/'.$type.'event',
+ 'component' => 'core'
];
}, $types);
}
@@ -3682,23 +3713,8 @@ function calendar_get_allowed_event_types(int $courseid = null) {
if (!empty($courseid) && $courseid != SITEID) {
$context = \context_course::instance($courseid);
- $groups = groups_get_all_groups($courseid);
-
$types['user'] = has_capability('moodle/calendar:manageownentries', $context);
-
- if (has_capability('moodle/calendar:manageentries', $context) || !empty($CFG->calendar_adminseesall)) {
- $types['course'] = true;
-
- $types['group'] = (!empty($groups) && has_capability('moodle/site:accessallgroups', $context))
- || array_filter($groups, function($group) use ($USER) {
- return groups_is_member($group->id);
- });
- } else if (has_capability('moodle/calendar:managegroupentries', $context)) {
- $types['group'] = (!empty($groups) && has_capability('moodle/site:accessallgroups', $context))
- || array_filter($groups, function($group) use ($USER) {
- return groups_is_member($group->id);
- });
- }
+ calendar_internal_update_course_and_group_permission($courseid, $context, $types);
}
if (has_capability('moodle/calendar:manageentries', \context_course::instance(SITEID))) {
@@ -3783,23 +3799,7 @@ function calendar_get_allowed_event_types(int $courseid = null) {
context_helper::preload_from_record($coursewithgroup);
$context = context_course::instance($coursewithgroup->id);
- if (has_capability('moodle/calendar:manageentries', $context)) {
- // The user has access to manage calendar entries for the whole course.
- // This includes groups if they have the accessallgroups capability.
- $types['course'] = true;
- if (has_capability('moodle/site:accessallgroups', $context)) {
- // The user also has access to all groups so they can add calendar entries to any group.
- // The manageentries capability overrides the managegroupentries capability.
- $types['group'] = true;
- break;
- }
-
- if (empty($types['group']) && has_capability('moodle/calendar:managegroupentries', $context)) {
- // The user has the managegroupentries capability.
- // If they have access to _any_ group, then they can create calendar entries within that group.
- $types['group'] = !empty(groups_get_all_groups($coursewithgroup->id, $USER->id));
- }
- }
+ calendar_internal_update_course_and_group_permission($coursewithgroup->id, $context, $types);
// Okay, course and group event types are allowed, no need to keep the loop iteration.
if ($types['course'] == true && $types['group'] == true) {
@@ -3833,3 +3833,43 @@ function calendar_get_allowed_event_types(int $courseid = null) {
return $types;
}
+
+/**
+ * Given a course id, and context, updates the permission types array to add the 'course' or 'group'
+ * permission if it is relevant for that course.
+ *
+ * For efficiency, if they already have 'course' or 'group' then it skips checks.
+ *
+ * Do not call this function directly, it is only for use by calendar_get_allowed_event_types().
+ *
+ * @param int $courseid Course id
+ * @param context $context Context for that course
+ * @param array $types Current permissions
+ */
+function calendar_internal_update_course_and_group_permission(int $courseid, context $context, array &$types) {
+ if (!$types['course']) {
+ // If they have manageentries permission on the course, then they can update this course.
+ if (has_capability('moodle/calendar:manageentries', $context)) {
+ $types['course'] = true;
+ }
+ }
+ // To update group events they must have EITHER manageentries OR managegroupentries.
+ if (!$types['group'] && (has_capability('moodle/calendar:manageentries', $context) ||
+ has_capability('moodle/calendar:managegroupentries', $context))) {
+ // And they also need for a group to exist on the course.
+ $groups = groups_get_all_groups($courseid);
+ if (!empty($groups)) {
+ // And either accessallgroups, or belong to one of the groups.
+ if (has_capability('moodle/site:accessallgroups', $context)) {
+ $types['group'] = true;
+ } else {
+ foreach ($groups as $group) {
+ if (groups_is_member($group->id)) {
+ $types['group'] = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/calendar/managesubscriptions.php b/calendar/managesubscriptions.php
index 4837733629e37..9c6af0adacc47 100644
--- a/calendar/managesubscriptions.php
+++ b/calendar/managesubscriptions.php
@@ -127,8 +127,13 @@
$params = [];
$usedefaultfilters = true;
-if (!empty($courseid) && $courseid == SITEID && !empty($types['site'])) {
+
+if (!empty($types['site'])) {
$searches[] = "(eventtype = 'site')";
+ $usedefaultfilters = false;
+}
+
+if (!empty($types['user'])) {
$searches[] = "(eventtype = 'user' AND userid = :userid)";
$params['userid'] = $USER->id;
$usedefaultfilters = false;
@@ -140,9 +145,14 @@
$usedefaultfilters = false;
}
-if (!empty($categoryid) && !empty($types['category'])) {
- $searches[] = "(eventtype = 'category' AND categoryid = :categoryid)";
- $params += ['categoryid' => $categoryid];
+if (!empty($types['category'])) {
+ if (!empty($categoryid)) {
+ $searches[] = "(eventtype = 'category' AND categoryid = :categoryid)";
+ $params += ['categoryid' => $categoryid];
+ } else {
+ $searches[] = "(eventtype = 'category')";
+ }
+
$usedefaultfilters = false;
}
diff --git a/calendar/renderer.php b/calendar/renderer.php
index a71b5fa5b520c..c84c8fcef0a62 100644
--- a/calendar/renderer.php
+++ b/calendar/renderer.php
@@ -161,7 +161,7 @@ public function event(calendar_event $event, $showactions=true) {
$deletelink = null;
}
- $commands = html_writer::start_tag('div', array('class' => 'commands pull-xs-right'));
+ $commands = html_writer::start_tag('div', array('class' => 'commands float-sm-right'));
$commands .= html_writer::start_tag('a', array('href' => $editlink));
$str = get_string('tt_editevent', 'calendar');
$commands .= $this->output->pix_icon('t/edit', $str);
@@ -205,9 +205,9 @@ public function event(calendar_event $event, $showactions=true) {
$output .= html_writer::tag('div', $event->courselink);
}
if (!empty($event->time)) {
- $output .= html_writer::tag('span', $event->time, array('class' => 'date pull-xs-right mr-1'));
+ $output .= html_writer::tag('span', $event->time, array('class' => 'date float-sm-right mr-1'));
} else {
- $attrs = array('class' => 'date pull-xs-right mr-1');
+ $attrs = array('class' => 'date float-sm-right mr-1');
$output .= html_writer::tag('span', calendar_time_representation($event->timestart), $attrs);
}
diff --git a/calendar/templates/day_detailed.mustache b/calendar/templates/day_detailed.mustache
index fde6b2f44170d..2cb495040c33e 100644
--- a/calendar/templates/day_detailed.mustache
+++ b/calendar/templates/day_detailed.mustache
@@ -46,5 +46,9 @@
{{> core_calendar/header}}
{{> core_calendar/day_navigation }}
{{> core/overlay_loading}}
- {{> core_calendar/event_list }}
+ {{< core_calendar/event_list }}
+ {{$noeventsmessage}}
+ {{#str}} daywithnoevents, core_calendar {{/str}}
+ {{/noeventsmessage}}
+ {{/core_calendar/event_list}}
diff --git a/calendar/templates/event_details.mustache b/calendar/templates/event_details.mustache
index 86fcda4cc9b53..1a1516fef7d37 100644
--- a/calendar/templates/event_details.mustache
+++ b/calendar/templates/event_details.mustache
@@ -59,10 +59,12 @@
{{#pix}} i/calendareventtime, core, {{#str}} when, core_calendar {{/str}} {{/pix}}
{{{formattedtime}}}
-
-
{{#pix}} i/calendar, core, {{#str}} eventtype, core_calendar {{/str}} {{/pix}}
-
{{normalisedeventtypetext}}
-
+{{#normalisedeventtypetext}}
+
+
{{#pix}} i/calendar, core, {{#str}} eventtype, core_calendar {{/str}} {{/pix}}
+
{{normalisedeventtypetext}}
+
+{{/normalisedeventtypetext}}
{{#description}}
{{#pix}} i/calendareventdescription, core, {{#str}} description {{/str}} {{/pix}}
diff --git a/calendar/templates/event_icon.mustache b/calendar/templates/event_icon.mustache
index fb88bd6c6eab1..ea61b32cf9326 100644
--- a/calendar/templates/event_icon.mustache
+++ b/calendar/templates/event_icon.mustache
@@ -37,5 +37,5 @@
{{#pix}} icon, {{modulename}} {{/pix}}
{{/modulename}}
{{^modulename}}
- {{#pix}} i/{{eventtype}}event, core {{/pix}}
+ {{#icon}}{{#pix}} {{key}}, {{component}}, {{alttext}} {{/pix}}{{/icon}}
{{/modulename}}
diff --git a/calendar/templates/event_list.mustache b/calendar/templates/event_list.mustache
index ae276ae20478a..63e4ca91709c6 100644
--- a/calendar/templates/event_list.mustache
+++ b/calendar/templates/event_list.mustache
@@ -37,7 +37,7 @@
{{/events}}
{{^events}}
- {{#str}}daywithnoevents, calendar{{/str}}
+ {{$noeventsmessage}}{{/noeventsmessage}}
{{/events}}
\ No newline at end of file
diff --git a/calendar/templates/month_mini.mustache b/calendar/templates/month_mini.mustache
index b1aa06f1b1409..cb3e22974c0c3 100644
--- a/calendar/templates/month_mini.mustache
+++ b/calendar/templates/month_mini.mustache
@@ -136,12 +136,7 @@
{{$content}}
{{#events}}
- {{#modulename}}
- {{#pix}} icon, {{modulename}} {{/pix}}
- {{/modulename}}
- {{^modulename}}
- {{#pix}} i/{{eventtype}}event, core {{/pix}}
- {{/modulename}}
+ {{> core_calendar/event_icon}}
{{{popupname}}}
{{/events}}
diff --git a/calendar/templates/upcoming_detailed.mustache b/calendar/templates/upcoming_detailed.mustache
index a1b070b790810..af33d99e4cbbb 100644
--- a/calendar/templates/upcoming_detailed.mustache
+++ b/calendar/templates/upcoming_detailed.mustache
@@ -34,5 +34,9 @@
{{> core_calendar/header}}
{{> core/overlay_loading}}
- {{> core_calendar/event_list }}
+ {{< core_calendar/event_list }}
+ {{$noeventsmessage}}
+ {{#str}} noupcomingevents, core_calendar {{/str}}
+ {{/noeventsmessage}}
+ {{/core_calendar/event_list}}
diff --git a/calendar/tests/behat/behat_calendar.php b/calendar/tests/behat/behat_calendar.php
index 0bd835cc66606..1c6cb4ccb3066 100644
--- a/calendar/tests/behat/behat_calendar.php
+++ b/calendar/tests/behat/behat_calendar.php
@@ -124,4 +124,16 @@ public function i_view_the_calendar_for($month, $year) {
$this->getSession()->visit($this->locate_path('/calendar/view.php?view=month&course=1&time='.$time));
}
+
+ /**
+ * Navigate to site calendar.
+ *
+ * @Given /^I am viewing site calendar$/
+ * @throws coding_exception
+ * @return void
+ */
+ public function i_am_viewing_site_calendar() {
+ $url = new moodle_url('/calendar/view.php', ['view' => 'month']);
+ $this->getSession()->visit($this->locate_path($url->out_as_local_url(false)));
+ }
}
diff --git a/calendar/tests/behat/calendar.feature b/calendar/tests/behat/calendar.feature
index cb681d0d53245..5f1ffaf50438f 100644
--- a/calendar/tests/behat/calendar.feature
+++ b/calendar/tests/behat/calendar.feature
@@ -14,6 +14,8 @@ Feature: Perform basic calendar functionality
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
+ | Course 2 | C2 | topics |
+ | Course 3 | C3 | topics |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
@@ -177,3 +179,62 @@ Feature: Perform basic calendar functionality
And I set the field "Type of event" to "Course"
When I click on "Save" "button"
And I should see "Select a course" in the "Course" "form_row"
+
+ @javascript
+ Scenario: Default event type selection in the event form
+ Given I log in as "teacher1"
+ When I am viewing site calendar
+ And I click on "New event" "button"
+ Then the field "Type of event" matches value "User"
+ And I am on "Course 1" course homepage
+ And I follow "This month"
+ When I click on "New event" "button"
+ Then the field "Type of event" matches value "Course"
+
+ @javascript
+ Scenario: Admin can only see all courses if calendar_adminseesall setting is enabled.
+ Given I log in as "admin"
+ And I am on "Course 1" course homepage
+ And I enrol "admin" user as "Teacher"
+ And I am viewing site calendar
+ And I click on "New event" "button"
+ And I set the field "Type of event" to "Course"
+ When I open the autocomplete suggestions list
+ Then I should see "Course 1" in the ".form-autocomplete-suggestions" "css_element"
+ And I should not see "Course 2" in the ".form-autocomplete-suggestions" "css_element"
+ And I should not see "Course 3" in the ".form-autocomplete-suggestions" "css_element"
+ And I click on "Close" "button"
+ And I am on site homepage
+ And I navigate to "Appearance > Calendar" in site administration
+ And I set the field "Admins see all" to "1"
+ And I press "Save changes"
+ And I am viewing site calendar
+ And I click on "New event" "button"
+ And I set the field "Type of event" to "Course"
+ When I open the autocomplete suggestions list
+ Then I should see "Course 1" in the ".form-autocomplete-suggestions" "css_element"
+ And I should see "Course 2" in the ".form-autocomplete-suggestions" "css_element"
+ And I should see "Course 3" in the ".form-autocomplete-suggestions" "css_element"
+
+ @javascript
+ Scenario: Students can only see user event type by default.
+ Given I log in as "student1"
+ And I am viewing site calendar
+ When I click on "New event" "button"
+ Then I should see "User" in the "div#fitem_id_staticeventtype" "css_element"
+ And I am on "Course 1" course homepage
+ And I follow "This month"
+ When I click on "New event" "button"
+ Then I should see "User" in the "div#fitem_id_staticeventtype" "css_element"
+ And I click on "Close" "button"
+ And I log out
+ Given I log in as "admin"
+ And I navigate to "Appearance > Calendar" in site administration
+ And I set the field "Admins see all" to "1"
+ And I press "Save changes"
+ And I log out
+ Given I log in as "student1"
+ And I am on "Course 1" course homepage
+ And I follow "This month"
+ When I click on "New event" "button"
+ Then I should see "User" in the "div#fitem_id_staticeventtype" "css_element"
diff --git a/calendar/tests/behat/calendar_import.feature b/calendar/tests/behat/calendar_import.feature
index a2c47cd5af2b8..2ad027a7b7b9b 100644
--- a/calendar/tests/behat/calendar_import.feature
+++ b/calendar/tests/behat/calendar_import.feature
@@ -47,3 +47,30 @@ Feature: Import and edit calendar events
And I view the calendar for "2" "2017"
And I should not see "Event on 2-25-2017"
And I should not see "Event on 2-20-2017"
+
+ Scenario: Import events using different event types.
+ Given I log in as "admin"
+ And I view the calendar for "1" "2016"
+ And I press "Manage subscriptions"
+ And I set the following fields to these values:
+ | Calendar name | Test Import |
+ | Import from | Calendar file (.ics) |
+ | Type of event | User |
+ And I upload "calendar/tests/fixtures/import.ics" file to "Calendar file (.ics)" filemanager
+ And I press "Add"
+ And I should see "User events"
+ And I set the following fields to these values:
+ | Calendar name | Test Import |
+ | Import from | Calendar file (.ics) |
+ | Type of event | Category |
+ | Category | Miscellaneous |
+ And I upload "calendar/tests/fixtures/import.ics" file to "Calendar file (.ics)" filemanager
+ And I press "Add"
+ And I should see "Category events"
+ And I set the following fields to these values:
+ | Calendar name | Test Import |
+ | Import from | Calendar file (.ics) |
+ | Type of event | Site |
+ And I upload "calendar/tests/fixtures/import.ics" file to "Calendar file (.ics)" filemanager
+ And I press "Add"
+ And I should see "Site events"
diff --git a/calendar/tests/lib_test.php b/calendar/tests/lib_test.php
index 35809ec18b7c5..94a3cb4c9f4d0 100644
--- a/calendar/tests/lib_test.php
+++ b/calendar/tests/lib_test.php
@@ -227,6 +227,24 @@ public function test_add_subscription() {
calendar_import_icalendar_events($ical, null, $sub->id);
$count = $DB->count_records('event', array('subscriptionid' => $sub->id));
$this->assertEquals($count, 1);
+
+ // Test for ICS file with repeated events.
+ $subscription = new stdClass();
+ $subscription->name = 'Repeated events';
+ $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE;
+ $subscription->eventtype = 'site';
+ $id = calendar_add_subscription($subscription);
+ $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/repeated_events.ics');
+ $ical = new iCalendar();
+ $ical->unserialize($calendar);
+ $this->assertEquals($ical->parser_errors, []);
+
+ $sub = calendar_get_subscription($id);
+ $output = calendar_import_icalendar_events($ical, null, $sub->id);
+ $this->assertStringNotContainsString('Events deleted: 17', $output);
+ $this->assertStringContainsString('Events imported: 1', $output);
+ $this->assertStringContainsString('Events skipped: 0', $output);
+ $this->assertStringContainsString('Events updated: 0', $output);
}
/**
@@ -546,6 +564,10 @@ public function test_calendar_get_allowed_event_types_course() {
$this->setUser($user);
+ // In general for all courses, they don't have the ability to add course events yet.
+ $types = calendar_get_allowed_event_types();
+ $this->assertFalse($types['course']);
+
assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context1, true);
assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context2, true);
@@ -554,12 +576,20 @@ public function test_calendar_get_allowed_event_types_course() {
$types = calendar_get_allowed_event_types($course1->id);
$this->assertTrue($types['course']);
+ // If calling function without specified course, there is still a course where they have it.
+ $types = calendar_get_allowed_event_types();
+ $this->assertTrue($types['course']);
+
assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context1, true);
// The user only now has the correct capability in both course 1 and 2 so we
// expect both to be in the results.
$types = calendar_get_allowed_event_types($course3->id);
$this->assertFalse($types['course']);
+
+ // They now do not have permission in any course.
+ $types = calendar_get_allowed_event_types();
+ $this->assertFalse($types['course']);
}
public function test_calendar_get_allowed_event_types_group_no_acces_to_diff_groups() {
@@ -582,6 +612,11 @@ public function test_calendar_get_allowed_event_types_group_no_acces_to_diff_gro
$types = calendar_get_allowed_event_types($course->id);
$this->assertTrue($types['course']);
$this->assertFalse($types['group']);
+
+ // Same result applies when not providing a specific course as they are only on one course.
+ $types = calendar_get_allowed_event_types();
+ $this->assertTrue($types['course']);
+ $this->assertFalse($types['group']);
}
public function test_calendar_get_allowed_event_types_group_no_groups() {
@@ -598,6 +633,12 @@ public function test_calendar_get_allowed_event_types_group_no_groups() {
// no groups so we shouldn't see a group type.
$types = calendar_get_allowed_event_types($course->id);
$this->assertTrue($types['course']);
+ $this->assertFalse($types['group']);
+
+ // Same result applies when not providing a specific course as they are only on one course.
+ $types = calendar_get_allowed_event_types();
+ $this->assertTrue($types['course']);
+ $this->assertFalse($types['group']);
}
public function test_calendar_get_allowed_event_types_group_access_all_groups() {
@@ -623,7 +664,12 @@ public function test_calendar_get_allowed_event_types_group_access_all_groups()
// the accessallgroups capability.
$types = calendar_get_allowed_event_types($course1->id);
$this->assertTrue($types['group']);
+
+ // Same result applies when not providing a specific course as they are only on one course.
+ $types = calendar_get_allowed_event_types();
+ $this->assertTrue($types['group']);
}
+
public function test_calendar_get_allowed_event_types_group_no_access_all_groups() {
$generator = $this->getDataGenerator();
$user = $generator->create_user();
@@ -642,10 +688,87 @@ public function test_calendar_get_allowed_event_types_group_no_access_all_groups
// groups that they are not a member of.
$types = calendar_get_allowed_event_types($course->id);
$this->assertFalse($types['group']);
+
+ // Same result applies when not providing a specific course as they are only on one course.
+ $types = calendar_get_allowed_event_types();
+ $this->assertFalse($types['group']);
+
assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context, true);
$types = calendar_get_allowed_event_types($course->id);
$this->assertTrue($types['group']);
+
+ // Same result applies when not providing a specific course as they are only on one course.
+ $types = calendar_get_allowed_event_types();
+ $this->assertTrue($types['group']);
+ }
+
+ public function test_calendar_get_allowed_event_types_group_cap_no_groups() {
+ $generator = $this->getDataGenerator();
+ $user = $generator->create_user();
+ $course = $generator->create_course();
+ $context = context_course::instance($course->id);
+ $roleid = $generator->create_role();
+ $group = $generator->create_group(['courseid' => $course->id]);
+ $generator->enrol_user($user->id, $course->id, 'student');
+ $generator->role_assign($roleid, $user->id, $context->id);
+ assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true);
+
+ $this->setUser($user);
+ $types = calendar_get_allowed_event_types($course->id);
+ $this->assertFalse($types['course']);
+ $this->assertFalse($types['group']);
+
+ // Check without specifying a course (same result as user only has one course).
+ $types = calendar_get_allowed_event_types();
+ $this->assertFalse($types['course']);
+ $this->assertFalse($types['group']);
+ }
+
+ public function test_calendar_get_allowed_event_types_group_cap_has_group() {
+ $generator = $this->getDataGenerator();
+ $user = $generator->create_user();
+ $course = $generator->create_course();
+ $context = context_course::instance($course->id);
+ $roleid = $generator->create_role();
+ $group = $generator->create_group(['courseid' => $course->id]);
+ $generator->enrol_user($user->id, $course->id, 'student');
+ $generator->role_assign($roleid, $user->id, $context->id);
+ groups_add_member($group, $user);
+ assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true);
+
+ $this->setUser($user);
+ $types = calendar_get_allowed_event_types($course->id);
+ $this->assertFalse($types['course']);
+ $this->assertTrue($types['group']);
+
+ // Check without specifying a course (same result as user only has one course).
+ $types = calendar_get_allowed_event_types();
+ $this->assertFalse($types['course']);
+ $this->assertTrue($types['group']);
+ }
+
+ public function test_calendar_get_allowed_event_types_group_cap_access_all_groups() {
+ $generator = $this->getDataGenerator();
+ $user = $generator->create_user();
+ $course = $generator->create_course();
+ $context = context_course::instance($course->id);
+ $roleid = $generator->create_role();
+ $group = $generator->create_group(['courseid' => $course->id]);
+ $generator->enrol_user($user->id, $course->id, 'student');
+ $generator->role_assign($roleid, $user->id, $context->id);
+ assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true);
+ assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context, true);
+
+ $this->setUser($user);
+ $types = calendar_get_allowed_event_types($course->id);
+ $this->assertFalse($types['course']);
+ $this->assertTrue($types['group']);
+
+ // Check without specifying a course (same result as user only has one course).
+ $types = calendar_get_allowed_event_types();
+ $this->assertFalse($types['course']);
+ $this->assertTrue($types['group']);
}
/**
@@ -772,4 +895,72 @@ public function test_calendar_set_filters_logged_in_another_user() {
$this->assertEquals(array($coursegroups[$courses[0]->id][1]->id), $groupids);
$this->assertEquals($users[1]->id, $userid);
}
+
+ /**
+ * Test for calendar_view_event_allowed for course event types.
+ */
+ public function test_calendar_view_event_allowed_course_event() {
+ global $USER;
+
+ $this->setAdminUser();
+
+ $generator = $this->getDataGenerator();
+
+ // A student in a course.
+ $student = $generator->create_user();
+ // Some user not enrolled in any course.
+ $someuser = $generator->create_user();
+
+ // A course with manual enrolments.
+ $manualcourse = $generator->create_course();
+
+ // Enrol the student to the manual enrolment course.
+ $generator->enrol_user($student->id, $manualcourse->id);
+
+ // A course that allows guest access.
+ $guestcourse = $generator->create_course(
+ (object)[
+ 'shortname' => 'guestcourse',
+ 'enrol_guest_status_0' => ENROL_INSTANCE_ENABLED,
+ 'enrol_guest_password_0' => ''
+ ]);
+
+ $manualevent = (object)[
+ 'name' => 'Manual course event',
+ 'description' => '',
+ 'format' => 1,
+ 'categoryid' => 0,
+ 'courseid' => $manualcourse->id,
+ 'groupid' => 0,
+ 'userid' => $USER->id,
+ 'modulename' => 0,
+ 'instance' => 0,
+ 'eventtype' => 'course',
+ 'timestart' => time(),
+ 'timeduration' => 86400,
+ 'visible' => 1
+ ];
+ $caleventmanual = calendar_event::create($manualevent, false);
+
+ // Create a course event for the course with guest access.
+ $guestevent = clone $manualevent;
+ $guestevent->name = 'Guest course event';
+ $guestevent->courseid = $guestcourse->id;
+ $caleventguest = calendar_event::create($guestevent, false);
+
+ // Viewing as admin.
+ $this->assertTrue(calendar_view_event_allowed($caleventmanual));
+ $this->assertTrue(calendar_view_event_allowed($caleventguest));
+
+ // Viewing as someone enrolled in a course.
+ $this->setUser($student);
+ $this->assertTrue(calendar_view_event_allowed($caleventmanual));
+
+ // Viewing as someone not enrolled in any course.
+ $this->setUser($someuser);
+ // Viewing as someone not enrolled in a course without guest access on.
+ $this->assertFalse(calendar_view_event_allowed($caleventmanual));
+ // Viewing as someone not enrolled in a course with guest access on.
+ $this->assertTrue(calendar_view_event_allowed($caleventguest));
+ }
}
diff --git a/calendar/view.php b/calendar/view.php
index 96f39f649e928..dea7508ae5d07 100644
--- a/calendar/view.php
+++ b/calendar/view.php
@@ -52,11 +52,23 @@
$categoryid = optional_param('category', null, PARAM_INT);
$courseid = optional_param('course', SITEID, PARAM_INT);
$view = optional_param('view', 'upcoming', PARAM_ALPHA);
+$day = optional_param('cal_d', 0, PARAM_INT);
+$mon = optional_param('cal_m', 0, PARAM_INT);
+$year = optional_param('cal_y', 0, PARAM_INT);
$time = optional_param('time', 0, PARAM_INT);
$lookahead = optional_param('lookahead', null, PARAM_INT);
$url = new moodle_url('/calendar/view.php');
+// If a day, month and year were passed then convert it to a timestamp. If these were passed
+// then we can assume the day, month and year are passed as Gregorian, as no where in core
+// should we be passing these values rather than the time. This is done for BC.
+if (!empty($day) && !empty($mon) && !empty($year)) {
+ if (checkdate($mon, $day, $year)) {
+ $time = make_timestamp($year, $mon, $day);
+ }
+}
+
if (empty($time)) {
$time = time();
}
diff --git a/comment/lib.php b/comment/lib.php
index f8e9f23e4bd18..94c2e92bb1dde 100644
--- a/comment/lib.php
+++ b/comment/lib.php
@@ -564,7 +564,7 @@ public function get_comments($page = '') {
c.commentarea = :commentarea AND
c.itemid = :itemid AND
$componentwhere
- ORDER BY c.timecreated DESC";
+ ORDER BY c.timecreated DESC, c.id DESC";
$params['contextid'] = $this->contextid;
$params['commentarea'] = $this->commentarea;
$params['itemid'] = $this->itemid;
diff --git a/comment/tests/externallib_test.php b/comment/tests/externallib_test.php
index c6a7433812052..4d81801722964 100644
--- a/comment/tests/externallib_test.php
+++ b/comment/tests/externallib_test.php
@@ -96,17 +96,18 @@ public function test_get_comments() {
// We need to add the comments manually, the comment API uses the global OUTPUT and this is going to make the WS to fail.
$newcmt = new stdClass;
+ $timecreated = time();
$newcmt->contextid = $context->id;
$newcmt->commentarea = 'database_entry';
$newcmt->itemid = $recordid;
$newcmt->content = 'New comment';
$newcmt->format = 0;
$newcmt->userid = $user->id;
- $newcmt->timecreated = time();
+ $newcmt->timecreated = $timecreated;
$cmtid1 = $DB->insert_record('comments', $newcmt);
$newcmt->content = 'New comment 2';
- $newcmt->timecreated = time() + 1;
+ $newcmt->timecreated = $timecreated;
$cmtid2 = $DB->insert_record('comments', $newcmt);
$contextlevel = 'module';
diff --git a/competency/classes/api.php b/competency/classes/api.php
index ffcda6b7fedb8..f231958d4454b 100644
--- a/competency/classes/api.php
+++ b/competency/classes/api.php
@@ -1231,7 +1231,7 @@ public static function list_course_module_competencies($cmorid) {
$result = array();
// TODO We could improve the performance of this into one single query.
- $coursemodulecompetencies = course_competency::list_course_module_competencies($cm->id);
+ $coursemodulecompetencies = course_module_competency::list_course_module_competencies($cm->id);
$competencies = course_module_competency::list_competencies($cm->id);
// Build the return values.
@@ -4777,6 +4777,40 @@ public static function hook_cohort_deleted(\stdClass $cohort) {
$DB->delete_records(template_cohort::TABLE, array('cohortid' => $cohort->id));
}
+ /**
+ * Action to perform when a user is deleted.
+ *
+ * @param int $userid The user id.
+ */
+ public static function hook_user_deleted($userid) {
+ global $DB;
+
+ $usercompetencies = $DB->get_records(user_competency::TABLE, ['userid' => $userid], '', 'id');
+ foreach ($usercompetencies as $usercomp) {
+ $DB->delete_records(evidence::TABLE, ['usercompetencyid' => $usercomp->id]);
+ }
+
+ $DB->delete_records(user_competency::TABLE, ['userid' => $userid]);
+ $DB->delete_records(user_competency_course::TABLE, ['userid' => $userid]);
+ $DB->delete_records(user_competency_plan::TABLE, ['userid' => $userid]);
+
+ // Delete any associated files.
+ $fs = get_file_storage();
+ $context = context_user::instance($userid);
+ $userevidences = $DB->get_records(user_evidence::TABLE, ['userid' => $userid], '', 'id');
+ foreach ($userevidences as $userevidence) {
+ $DB->delete_records(user_evidence_competency::TABLE, ['userevidenceid' => $userevidence->id]);
+ $DB->delete_records(user_evidence::TABLE, ['id' => $userevidence->id]);
+ $fs->delete_area_files($context->id, 'core_competency', 'userevidence', $userevidence->id);
+ }
+
+ $userplans = $DB->get_records(plan::TABLE, ['userid' => $userid], '', 'id');
+ foreach ($userplans as $userplan) {
+ $DB->delete_records(plan_competency::TABLE, ['planid' => $userplan->id]);
+ $DB->delete_records(plan::TABLE, ['id' => $userplan->id]);
+ }
+ }
+
/**
* Manually grade a user competency.
*
diff --git a/competency/tests/api_test.php b/competency/tests/api_test.php
index 3ecf3e9942daf..ffe15e344a23a 100644
--- a/competency/tests/api_test.php
+++ b/competency/tests/api_test.php
@@ -2757,6 +2757,16 @@ public function test_list_course_modules_using_competency() {
$result = api::list_course_module_competencies_in_course_module($cm->id);
$this->assertEquals($result[0]->get('competencyid'), $c->get('id'));
$this->assertEquals($result[1]->get('competencyid'), $c2->get('id'));
+
+ // Now get the course competency and coursemodule competency together.
+ $result = api::list_course_module_competencies($cm->id);
+ // Now we should have an array and each element of the array should have a competency and
+ // a coursemodulecompetency.
+ foreach ($result as $instance) {
+ $cmc = $instance['coursemodulecompetency'];
+ $c = $instance['competency'];
+ $this->assertEquals($cmc->get('competencyid'), $c->get('id'));
+ }
}
/**
diff --git a/competency/tests/hooks_test.php b/competency/tests/hooks_test.php
index e8be7c41a9a12..c1890eac6f04c 100644
--- a/competency/tests/hooks_test.php
+++ b/competency/tests/hooks_test.php
@@ -207,4 +207,47 @@ public function test_hook_cohort_deleted() {
$this->assertEquals(1, \core_competency\template_cohort::count_records(array('templateid' => $t1->get('id'))));
$this->assertEquals(0, \core_competency\template_cohort::count_records(array('templateid' => $t2->get('id'))));
}
+
+ public function test_hook_user_deleted() {
+ $this->resetAfterTest();
+ $dg = $this->getDataGenerator();
+ $ccg = $dg->get_plugin_generator('core_competency');
+
+ $u1 = $dg->create_user();
+
+ $framework = $ccg->create_framework();
+ $comp1 = $ccg->create_competency(['competencyframeworkid' => $framework->get('id')]);
+ $comp2 = $ccg->create_competency(['competencyframeworkid' => $framework->get('id')]);
+
+ $c1 = $dg->create_course();
+ $cc1a = $ccg->create_course_competency(['competencyid' => $comp1->get('id'), 'courseid' => $c1->id]);
+ $cc1b = $ccg->create_course_competency(['competencyid' => $comp2->get('id'), 'courseid' => $c1->id]);
+ $assign1a = $dg->create_module('assign', ['course' => $c1]);
+ $assign1b = $dg->create_module('assign', ['course' => $c1]);
+ $cmc1a = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign1a->cmid]);
+ $cmc1b = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign1b->cmid]);
+ $ucc1a = $ccg->create_user_competency_course(['competencyid' => $comp1->get('id'), 'courseid' => $c1->id,
+ 'userid' => $u1->id]);
+ $ucc1b = $ccg->create_user_competency_course(['competencyid' => $comp2->get('id'), 'courseid' => $c1->id,
+ 'userid' => $u1->id]);
+
+ $c2 = $dg->create_course();
+ $cc2a = $ccg->create_course_competency(['competencyid' => $comp1->get('id'), 'courseid' => $c2->id]);
+ $cc2b = $ccg->create_course_competency(['competencyid' => $comp2->get('id'), 'courseid' => $c2->id]);
+ $assign2a = $dg->create_module('assign', ['course' => $c2]);
+ $assign2b = $dg->create_module('assign', ['course' => $c2]);
+ $cmc2a = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign2a->cmid]);
+ $cmc2b = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign2b->cmid]);
+ $ucc2a = $ccg->create_user_competency_course(['competencyid' => $comp1->get('id'), 'courseid' => $c2->id,
+ 'userid' => $u1->id]);
+ $ucc2b = $ccg->create_user_competency_course(['competencyid' => $comp2->get('id'), 'courseid' => $c2->id,
+ 'userid' => $u1->id]);
+
+ reset_course_userdata((object) ['id' => $c1->id, 'reset_competency_ratings' => true]);
+
+ delete_user($u1);
+
+ // Assert the records don't exist anymore.
+ $this->assertEquals(0, user_competency_course::count_records(['courseid' => $c1->id, 'userid' => $u1->id]));
+ }
}
diff --git a/composer.json b/composer.json
index 6dc963d3ddce5..a42f7e63e8c2a 100644
--- a/composer.json
+++ b/composer.json
@@ -4,10 +4,17 @@
"description": "Moodle - the world's open source learning platform",
"type": "project",
"homepage": "https://moodle.org",
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "https://github.com/moodlehq/php-webdriver.git"
+ }
+ ],
"require-dev": {
"phpunit/phpunit": "7.5.*",
"phpunit/dbunit": "4.0.*",
- "moodlehq/behat-extension": "3.37.0",
- "mikey179/vfsstream": "^1.6"
+ "moodlehq/behat-extension": "3.37.3",
+ "mikey179/vfsstream": "^1.6",
+ "instaclick/php-webdriver": "dev-local as 1.x-dev"
}
}
diff --git a/composer.lock b/composer.lock
index 948ff212bcddb..b36087ddb2b9c 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,46 +4,42 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "3517a4473544055cd8523bb076cad8f6",
+ "content-hash": "ee640e103837d18775219772bd0bfb92",
"packages": [],
"packages-dev": [
{
"name": "behat/behat",
- "version": "v3.3.1",
+ "version": "v3.5.0",
"source": {
"type": "git",
"url": "https://github.com/Behat/Behat.git",
- "reference": "44a58c1480d6144b2dc2c2bf02b9cef73c83840d"
+ "reference": "e4bce688be0c2029dc1700e46058d86428c63cab"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Behat/Behat/zipball/44a58c1480d6144b2dc2c2bf02b9cef73c83840d",
- "reference": "44a58c1480d6144b2dc2c2bf02b9cef73c83840d",
+ "url": "https://api.github.com/repos/Behat/Behat/zipball/e4bce688be0c2029dc1700e46058d86428c63cab",
+ "reference": "e4bce688be0c2029dc1700e46058d86428c63cab",
"shasum": ""
},
"require": {
- "behat/gherkin": "^4.4.4",
+ "behat/gherkin": "^4.5.1",
"behat/transliterator": "^1.2",
- "container-interop/container-interop": "^1.1",
+ "container-interop/container-interop": "^1.2",
"ext-mbstring": "*",
"php": ">=5.3.3",
+ "psr/container": "^1.0",
"symfony/class-loader": "~2.1||~3.0",
- "symfony/config": "~2.3||~3.0",
- "symfony/console": "~2.5||~3.0",
- "symfony/dependency-injection": "~2.1||~3.0",
- "symfony/event-dispatcher": "~2.1||~3.0",
- "symfony/translation": "~2.3||~3.0",
- "symfony/yaml": "~2.1||~3.0"
+ "symfony/config": "~2.3||~3.0||~4.0",
+ "symfony/console": "~2.7.40||^2.8.33||~3.3.15||^3.4.3||^4.0.3",
+ "symfony/dependency-injection": "~2.1||~3.0||~4.0",
+ "symfony/event-dispatcher": "~2.1||~3.0||~4.0",
+ "symfony/translation": "~2.3||~3.0||~4.0",
+ "symfony/yaml": "~2.1||~3.0||~4.0"
},
"require-dev": {
"herrera-io/box": "~1.6.1",
- "phpunit/phpunit": "~4.5",
- "symfony/process": "~2.5|~3.0"
- },
- "suggest": {
- "behat/mink-extension": "for integration with Mink testing framework",
- "behat/symfony2-extension": "for integration with Symfony2 web framework",
- "behat/yii-extension": "for integration with Yii web framework"
+ "phpunit/phpunit": "^4.8.36|^6.3",
+ "symfony/process": "~2.5|~3.0|~4.0"
},
"bin": [
"bin/behat"
@@ -51,7 +47,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.2.x-dev"
+ "dev-master": "3.5.x-dev"
}
},
"autoload": {
@@ -87,7 +83,7 @@
"symfony",
"testing"
],
- "time": "2017-05-15T16:49:16+00:00"
+ "time": "2018-08-10T18:56:51+00:00"
},
{
"name": "behat/gherkin",
@@ -625,27 +621,28 @@
},
{
"name": "guzzlehttp/guzzle",
- "version": "6.3.3",
+ "version": "6.4.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
- "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba"
+ "reference": "0895c932405407fd3a7368b6910c09a24d26db11"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba",
- "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/0895c932405407fd3a7368b6910c09a24d26db11",
+ "reference": "0895c932405407fd3a7368b6910c09a24d26db11",
"shasum": ""
},
"require": {
+ "ext-json": "*",
"guzzlehttp/promises": "^1.0",
- "guzzlehttp/psr7": "^1.4",
+ "guzzlehttp/psr7": "^1.6.1",
"php": ">=5.5"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
- "psr/log": "^1.0"
+ "psr/log": "^1.1"
},
"suggest": {
"psr/log": "Required for using the Log middleware"
@@ -657,12 +654,12 @@
}
},
"autoload": {
- "files": [
- "src/functions_include.php"
- ],
"psr-4": {
"GuzzleHttp\\": "src/"
- }
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -686,7 +683,7 @@
"rest",
"web service"
],
- "time": "2018-04-22T15:46:56+00:00"
+ "time": "2019-10-23T15:58:00+00:00"
},
{
"name": "guzzlehttp/promises",
@@ -741,33 +738,37 @@
},
{
"name": "guzzlehttp/psr7",
- "version": "1.5.2",
+ "version": "1.6.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
- "reference": "9f83dded91781a01c63574e387eaa769be769115"
+ "reference": "239400de7a173fe9901b9ac7c06497751f00727a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115",
- "reference": "9f83dded91781a01c63574e387eaa769be769115",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a",
+ "reference": "239400de7a173fe9901b9ac7c06497751f00727a",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0",
- "ralouphie/getallheaders": "^2.0.5"
+ "ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
+ "ext-zlib": "*",
"phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8"
},
+ "suggest": {
+ "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses"
+ },
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.5-dev"
+ "dev-master": "1.6-dev"
}
},
"autoload": {
@@ -804,20 +805,20 @@
"uri",
"url"
],
- "time": "2018-12-04T20:46:45+00:00"
+ "time": "2019-07-01T23:21:34+00:00"
},
{
"name": "instaclick/php-webdriver",
- "version": "1.4.5",
+ "version": "dev-local",
"source": {
"type": "git",
- "url": "https://github.com/instaclick/php-webdriver.git",
- "reference": "6fa959452e774dcaed543faad3a9d1a37d803327"
+ "url": "https://github.com/moodlehq/php-webdriver.git",
+ "reference": "3df827208ec104a9716aa8c30741e330da620c1e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/instaclick/php-webdriver/zipball/6fa959452e774dcaed543faad3a9d1a37d803327",
- "reference": "6fa959452e774dcaed543faad3a9d1a37d803327",
+ "url": "https://api.github.com/repos/moodlehq/php-webdriver/zipball/3df827208ec104a9716aa8c30741e330da620c1e",
+ "reference": "3df827208ec104a9716aa8c30741e330da620c1e",
"shasum": ""
},
"require": {
@@ -839,7 +840,6 @@
"WebDriver": "lib/"
}
},
- "notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
@@ -863,27 +863,30 @@
"webdriver",
"webtest"
],
- "time": "2017-06-30T04:02:48+00:00"
+ "support": {
+ "source": "https://github.com/moodlehq/php-webdriver/tree/local"
+ },
+ "time": "2019-08-14T02:10:24+00:00"
},
{
- "name": "mikey179/vfsStream",
- "version": "v1.6.6",
+ "name": "mikey179/vfsstream",
+ "version": "v1.6.7",
"source": {
"type": "git",
"url": "https://github.com/bovigo/vfsStream.git",
- "reference": "095238a0711c974ae5b4ebf4c4534a23f3f6c99d"
+ "reference": "2b544ac3a21bcc4dde5d90c4ae8d06f4319055fb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/095238a0711c974ae5b4ebf4c4534a23f3f6c99d",
- "reference": "095238a0711c974ae5b4ebf4c4534a23f3f6c99d",
+ "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/2b544ac3a21bcc4dde5d90c4ae8d06f4319055fb",
+ "reference": "2b544ac3a21bcc4dde5d90c4ae8d06f4319055fb",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.5"
+ "phpunit/phpunit": "^4.5|^5.0"
},
"type": "library",
"extra": {
@@ -909,30 +912,29 @@
],
"description": "Virtual file system to mock the real file system in unit tests.",
"homepage": "http://vfs.bovigo.org/",
- "time": "2019-04-08T13:54:32+00:00"
+ "time": "2019-08-01T01:38:37+00:00"
},
{
"name": "moodlehq/behat-extension",
- "version": "v3.37.0",
+ "version": "v3.37.3",
"source": {
"type": "git",
"url": "https://github.com/moodlehq/moodle-behat-extension.git",
- "reference": "ba8c4b8b323e05f7af128604f3f3dc60c953135a"
+ "reference": "c4b69596142fa297ba049e13f04f3b158dcc94e6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/moodlehq/moodle-behat-extension/zipball/ba8c4b8b323e05f7af128604f3f3dc60c953135a",
- "reference": "ba8c4b8b323e05f7af128604f3f3dc60c953135a",
+ "url": "https://api.github.com/repos/moodlehq/moodle-behat-extension/zipball/c4b69596142fa297ba049e13f04f3b158dcc94e6",
+ "reference": "c4b69596142fa297ba049e13f04f3b158dcc94e6",
"shasum": ""
},
"require": {
- "behat/behat": "3.3.*",
+ "behat/behat": "3.5.*",
"behat/mink": "~1.7",
"behat/mink-extension": "~2.2",
"behat/mink-goutte-driver": "~1.2",
"behat/mink-selenium2-driver": "~1.3",
- "guzzlehttp/guzzle": "^6.3",
- "php": ">=5.4.4",
+ "php": ">=7.1.0",
"symfony/process": "2.8.*"
},
"type": "library",
@@ -959,20 +961,20 @@
"Behat",
"moodle"
],
- "time": "2018-02-04T18:04:02+00:00"
+ "time": "2019-10-28T11:41:43+00:00"
},
{
"name": "myclabs/deep-copy",
- "version": "1.9.1",
+ "version": "1.9.3",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72"
+ "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72",
- "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea",
+ "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea",
"shasum": ""
},
"require": {
@@ -1007,7 +1009,7 @@
"object",
"object graph"
],
- "time": "2019-04-07T13:18:21+00:00"
+ "time": "2019-08-09T12:45:53+00:00"
},
{
"name": "phar-io/manifest",
@@ -1113,35 +1115,33 @@
},
{
"name": "phpdocumentor/reflection-common",
- "version": "1.0.1",
+ "version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
- "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
+ "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
- "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a",
+ "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a",
"shasum": ""
},
"require": {
- "php": ">=5.5"
+ "php": ">=7.1"
},
"require-dev": {
- "phpunit/phpunit": "^4.6"
+ "phpunit/phpunit": "~6"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
- "phpDocumentor\\Reflection\\": [
- "src"
- ]
+ "phpDocumentor\\Reflection\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1163,30 +1163,30 @@
"reflection",
"static analysis"
],
- "time": "2017-09-11T18:02:19+00:00"
+ "time": "2018-08-07T13:53:10+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
- "version": "4.3.1",
+ "version": "4.3.2",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c"
+ "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c",
- "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
+ "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
"shasum": ""
},
"require": {
"php": "^7.0",
- "phpdocumentor/reflection-common": "^1.0.0",
- "phpdocumentor/type-resolver": "^0.4.0",
+ "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0",
+ "phpdocumentor/type-resolver": "~0.4 || ^1.0.0",
"webmozart/assert": "^1.0"
},
"require-dev": {
- "doctrine/instantiator": "~1.0.5",
+ "doctrine/instantiator": "^1.0.5",
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^6.4"
},
@@ -1214,41 +1214,40 @@
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
- "time": "2019-04-30T17:48:53+00:00"
+ "time": "2019-09-12T14:27:41+00:00"
},
{
"name": "phpdocumentor/type-resolver",
- "version": "0.4.0",
+ "version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
+ "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
- "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9",
+ "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9",
"shasum": ""
},
"require": {
- "php": "^5.5 || ^7.0",
- "phpdocumentor/reflection-common": "^1.0"
+ "php": "^7.1",
+ "phpdocumentor/reflection-common": "^2.0"
},
"require-dev": {
- "mockery/mockery": "^0.9.4",
- "phpunit/phpunit": "^5.2||^4.8.24"
+ "ext-tokenizer": "^7.1",
+ "mockery/mockery": "~1",
+ "phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
- "phpDocumentor\\Reflection\\": [
- "src/"
- ]
+ "phpDocumentor\\Reflection\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1261,26 +1260,27 @@
"email": "me@mikevanriel.com"
}
],
- "time": "2017-07-14T14:27:02+00:00"
+ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
+ "time": "2019-08-22T18:11:29+00:00"
},
{
"name": "phpspec/prophecy",
- "version": "1.8.0",
+ "version": "1.9.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06"
+ "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
- "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203",
+ "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
- "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
"sebastian/comparator": "^1.1|^2.0|^3.0",
"sebastian/recursion-context": "^1.0|^2.0|^3.0"
},
@@ -1295,8 +1295,8 @@
}
},
"autoload": {
- "psr-0": {
- "Prophecy\\": "src/"
+ "psr-4": {
+ "Prophecy\\": "src/Prophecy"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1324,7 +1324,7 @@
"spy",
"stub"
],
- "time": "2018-08-05T17:53:17+00:00"
+ "time": "2019-10-03T11:07:50+00:00"
},
{
"name": "phpunit/dbunit",
@@ -1535,16 +1535,16 @@
},
{
"name": "phpunit/php-timer",
- "version": "2.1.1",
+ "version": "2.1.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "8b389aebe1b8b0578430bda0c7c95a829608e059"
+ "reference": "1038454804406b0b5f5f520358e78c1c2f71501e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b389aebe1b8b0578430bda0c7c95a829608e059",
- "reference": "8b389aebe1b8b0578430bda0c7c95a829608e059",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e",
+ "reference": "1038454804406b0b5f5f520358e78c1c2f71501e",
"shasum": ""
},
"require": {
@@ -1580,20 +1580,20 @@
"keywords": [
"timer"
],
- "time": "2019-02-20T10:12:59+00:00"
+ "time": "2019-06-07T04:22:29+00:00"
},
{
"name": "phpunit/php-token-stream",
- "version": "3.0.1",
+ "version": "3.1.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18"
+ "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18",
- "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff",
+ "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff",
"shasum": ""
},
"require": {
@@ -1606,7 +1606,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -1629,20 +1629,20 @@
"keywords": [
"tokenizer"
],
- "time": "2018-10-30T05:52:18+00:00"
+ "time": "2019-09-17T06:23:10+00:00"
},
{
"name": "phpunit/phpunit",
- "version": "7.5.9",
+ "version": "7.5.17",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "134669cf0eeac3f79bc7f0c793efbc158bffc160"
+ "reference": "4c92a15296e58191a4cd74cff3b34fc8e374174a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/134669cf0eeac3f79bc7f0c793efbc158bffc160",
- "reference": "134669cf0eeac3f79bc7f0c793efbc158bffc160",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4c92a15296e58191a4cd74cff3b34fc8e374174a",
+ "reference": "4c92a15296e58191a4cd74cff3b34fc8e374174a",
"shasum": ""
},
"require": {
@@ -1713,7 +1713,7 @@
"testing",
"xunit"
],
- "time": "2019-04-19T15:50:46+00:00"
+ "time": "2019-10-28T10:37:36+00:00"
},
{
"name": "psr/container",
@@ -1816,16 +1816,16 @@
},
{
"name": "psr/log",
- "version": "1.1.0",
+ "version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
- "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
+ "reference": "bf73deb2b3b896a9d9c75f3f0d88185d2faa27e2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
- "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/bf73deb2b3b896a9d9c75f3f0d88185d2faa27e2",
+ "reference": "bf73deb2b3b896a9d9c75f3f0d88185d2faa27e2",
"shasum": ""
},
"require": {
@@ -1834,7 +1834,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "1.1.x-dev"
}
},
"autoload": {
@@ -1859,28 +1859,28 @@
"psr",
"psr-3"
],
- "time": "2018-11-20T15:27:04+00:00"
+ "time": "2019-10-25T08:06:51+00:00"
},
{
"name": "ralouphie/getallheaders",
- "version": "2.0.5",
+ "version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/ralouphie/getallheaders.git",
- "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa"
+ "reference": "120b605dfeb996808c31b6477290a714d356e822"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa",
- "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa",
+ "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822",
"shasum": ""
},
"require": {
- "php": ">=5.3"
+ "php": ">=5.6"
},
"require-dev": {
- "phpunit/phpunit": "~3.7.0",
- "satooshi/php-coveralls": ">=1.0"
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpunit/phpunit": "^5 || ^6.5"
},
"type": "library",
"autoload": {
@@ -1899,7 +1899,7 @@
}
],
"description": "A polyfill for getallheaders.",
- "time": "2016-02-11T07:05:27+00:00"
+ "time": "2019-03-08T08:55:37+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
@@ -2121,16 +2121,16 @@
},
{
"name": "sebastian/exporter",
- "version": "3.1.0",
+ "version": "3.1.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "234199f4528de6d12aaa58b612e98f7d36adb937"
+ "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937",
- "reference": "234199f4528de6d12aaa58b612e98f7d36adb937",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e",
+ "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e",
"shasum": ""
},
"require": {
@@ -2157,6 +2157,10 @@
"BSD-3-Clause"
],
"authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
@@ -2165,17 +2169,13 @@
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@2bepublished.at"
- },
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- },
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
}
],
"description": "Provides the functionality to export PHP variables for visualization",
@@ -2184,7 +2184,7 @@
"export",
"exporter"
],
- "time": "2017-04-03T13:19:02+00:00"
+ "time": "2019-09-14T09:02:43+00:00"
},
{
"name": "sebastian/global-state",
@@ -2469,16 +2469,16 @@
},
{
"name": "symfony/browser-kit",
- "version": "v4.2.8",
+ "version": "v4.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
- "reference": "c09c18cca96d7067152f78956faf55346c338283"
+ "reference": "78b7611c45039e8ce81698be319851529bf040b1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/browser-kit/zipball/c09c18cca96d7067152f78956faf55346c338283",
- "reference": "c09c18cca96d7067152f78956faf55346c338283",
+ "url": "https://api.github.com/repos/symfony/browser-kit/zipball/78b7611c45039e8ce81698be319851529bf040b1",
+ "reference": "78b7611c45039e8ce81698be319851529bf040b1",
"shasum": ""
},
"require": {
@@ -2487,6 +2487,8 @@
},
"require-dev": {
"symfony/css-selector": "~3.4|~4.0",
+ "symfony/http-client": "^4.3",
+ "symfony/mime": "^4.3",
"symfony/process": "~3.4|~4.0"
},
"suggest": {
@@ -2495,7 +2497,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.2-dev"
+ "dev-master": "4.3-dev"
}
},
"autoload": {
@@ -2522,20 +2524,20 @@
],
"description": "Symfony BrowserKit Component",
"homepage": "https://symfony.com",
- "time": "2019-04-07T09:56:43+00:00"
+ "time": "2019-09-10T11:25:17+00:00"
},
{
"name": "symfony/class-loader",
- "version": "v3.4.27",
+ "version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/class-loader.git",
- "reference": "4459eef5298dedfb69f771186a580062b8516497"
+ "reference": "e212b06996819a2bce026a63da03b7182d05a690"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/class-loader/zipball/4459eef5298dedfb69f771186a580062b8516497",
- "reference": "4459eef5298dedfb69f771186a580062b8516497",
+ "url": "https://api.github.com/repos/symfony/class-loader/zipball/e212b06996819a2bce026a63da03b7182d05a690",
+ "reference": "e212b06996819a2bce026a63da03b7182d05a690",
"shasum": ""
},
"require": {
@@ -2578,36 +2580,36 @@
],
"description": "Symfony ClassLoader Component",
"homepage": "https://symfony.com",
- "time": "2019-01-16T09:39:14+00:00"
+ "time": "2019-08-20T13:31:17+00:00"
},
{
"name": "symfony/config",
- "version": "v3.4.27",
+ "version": "v4.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
- "reference": "177a276c01575253c95cefe0866e3d1b57637fe0"
+ "reference": "0acb26407a9e1a64a275142f0ae5e36436342720"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/config/zipball/177a276c01575253c95cefe0866e3d1b57637fe0",
- "reference": "177a276c01575253c95cefe0866e3d1b57637fe0",
+ "url": "https://api.github.com/repos/symfony/config/zipball/0acb26407a9e1a64a275142f0ae5e36436342720",
+ "reference": "0acb26407a9e1a64a275142f0ae5e36436342720",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8",
- "symfony/filesystem": "~2.8|~3.0|~4.0",
+ "php": "^7.1.3",
+ "symfony/filesystem": "~3.4|~4.0",
"symfony/polyfill-ctype": "~1.8"
},
"conflict": {
- "symfony/dependency-injection": "<3.3",
- "symfony/finder": "<3.3"
+ "symfony/finder": "<3.4"
},
"require-dev": {
- "symfony/dependency-injection": "~3.3|~4.0",
- "symfony/event-dispatcher": "~3.3|~4.0",
- "symfony/finder": "~3.3|~4.0",
- "symfony/yaml": "~3.0|~4.0"
+ "symfony/dependency-injection": "~3.4|~4.0",
+ "symfony/event-dispatcher": "~3.4|~4.0",
+ "symfony/finder": "~3.4|~4.0",
+ "symfony/messenger": "~4.1",
+ "symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"symfony/yaml": "To use the yaml reference dumper"
@@ -2615,7 +2617,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.4-dev"
+ "dev-master": "4.3-dev"
}
},
"autoload": {
@@ -2642,7 +2644,7 @@
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
- "time": "2019-02-23T15:06:07+00:00"
+ "time": "2019-09-19T15:51:53+00:00"
},
{
"name": "symfony/console",
@@ -2714,16 +2716,16 @@
},
{
"name": "symfony/css-selector",
- "version": "v3.4.27",
+ "version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
- "reference": "8ca29297c29b64fb3a1a135e71cb25f67f9fdccf"
+ "reference": "f819f71ae3ba6f396b4c015bd5895de7d2f1f85f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/css-selector/zipball/8ca29297c29b64fb3a1a135e71cb25f67f9fdccf",
- "reference": "8ca29297c29b64fb3a1a135e71cb25f67f9fdccf",
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/f819f71ae3ba6f396b4c015bd5895de7d2f1f85f",
+ "reference": "f819f71ae3ba6f396b4c015bd5895de7d2f1f85f",
"shasum": ""
},
"require": {
@@ -2748,14 +2750,14 @@
"MIT"
],
"authors": [
- {
- "name": "Jean-François Simon",
- "email": "jeanfrancois.simon@sensiolabs.com"
- },
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
+ {
+ "name": "Jean-François Simon",
+ "email": "jeanfrancois.simon@sensiolabs.com"
+ },
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
@@ -2763,20 +2765,20 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
- "time": "2019-01-16T09:39:14+00:00"
+ "time": "2019-10-01T11:57:37+00:00"
},
{
"name": "symfony/debug",
- "version": "v3.4.27",
+ "version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
- "reference": "681afbb26488903c5ac15e63734f1d8ac430c9b9"
+ "reference": "b3e7ce815d82196435d16dc458023f8fb6b36ceb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/debug/zipball/681afbb26488903c5ac15e63734f1d8ac430c9b9",
- "reference": "681afbb26488903c5ac15e63734f1d8ac430c9b9",
+ "url": "https://api.github.com/repos/symfony/debug/zipball/b3e7ce815d82196435d16dc458023f8fb6b36ceb",
+ "reference": "b3e7ce815d82196435d16dc458023f8fb6b36ceb",
"shasum": ""
},
"require": {
@@ -2819,7 +2821,7 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
- "time": "2019-04-11T09:48:14+00:00"
+ "time": "2019-09-19T15:32:51+00:00"
},
{
"name": "symfony/dependency-injection",
@@ -2893,16 +2895,16 @@
},
{
"name": "symfony/dom-crawler",
- "version": "v4.2.8",
+ "version": "v4.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
- "reference": "53c97769814c80a84a8403efcf3ae7ae966d53bb"
+ "reference": "e9f7b4d19d69b133bd638eeddcdc757723b4211f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/53c97769814c80a84a8403efcf3ae7ae966d53bb",
- "reference": "53c97769814c80a84a8403efcf3ae7ae966d53bb",
+ "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/e9f7b4d19d69b133bd638eeddcdc757723b4211f",
+ "reference": "e9f7b4d19d69b133bd638eeddcdc757723b4211f",
"shasum": ""
},
"require": {
@@ -2910,7 +2912,11 @@
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0"
},
+ "conflict": {
+ "masterminds/html5": "<2.6"
+ },
"require-dev": {
+ "masterminds/html5": "^2.6",
"symfony/css-selector": "~3.4|~4.0"
},
"suggest": {
@@ -2919,7 +2925,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.2-dev"
+ "dev-master": "4.3-dev"
}
},
"autoload": {
@@ -2946,20 +2952,20 @@
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
- "time": "2019-02-23T15:17:42+00:00"
+ "time": "2019-09-28T21:25:05+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v3.4.27",
+ "version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "a088aafcefb4eef2520a290ed82e4374092a6dff"
+ "reference": "3e922c4c3430b9de624e8a285dada5e61e230959"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a088aafcefb4eef2520a290ed82e4374092a6dff",
- "reference": "a088aafcefb4eef2520a290ed82e4374092a6dff",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3e922c4c3430b9de624e8a285dada5e61e230959",
+ "reference": "3e922c4c3430b9de624e8a285dada5e61e230959",
"shasum": ""
},
"require": {
@@ -3009,20 +3015,20 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
- "time": "2019-04-02T08:51:52+00:00"
+ "time": "2019-08-23T08:05:57+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v4.2.8",
+ "version": "v4.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "e16b9e471703b2c60b95f14d31c1239f68f11601"
+ "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/e16b9e471703b2c60b95f14d31c1239f68f11601",
- "reference": "e16b9e471703b2c60b95f14d31c1239f68f11601",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/9abbb7ef96a51f4d7e69627bc6f63307994e4263",
+ "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263",
"shasum": ""
},
"require": {
@@ -3032,7 +3038,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.2-dev"
+ "dev-master": "4.3-dev"
}
},
"autoload": {
@@ -3059,20 +3065,20 @@
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
- "time": "2019-02-07T11:40:08+00:00"
+ "time": "2019-08-20T14:07:54+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.11.0",
+ "version": "v1.12.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "82ebae02209c21113908c229e9883c419720738a"
+ "reference": "550ebaac289296ce228a706d0867afc34687e3f4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a",
- "reference": "82ebae02209c21113908c229e9883c419720738a",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4",
+ "reference": "550ebaac289296ce228a706d0867afc34687e3f4",
"shasum": ""
},
"require": {
@@ -3084,7 +3090,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.11-dev"
+ "dev-master": "1.12-dev"
}
},
"autoload": {
@@ -3100,13 +3106,13 @@
"MIT"
],
"authors": [
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- },
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
@@ -3117,20 +3123,20 @@
"polyfill",
"portable"
],
- "time": "2019-02-06T07:57:58+00:00"
+ "time": "2019-08-06T08:03:45+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.11.0",
+ "version": "v1.12.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "fe5e94c604826c35a32fa832f35bd036b6799609"
+ "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609",
- "reference": "fe5e94c604826c35a32fa832f35bd036b6799609",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17",
+ "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17",
"shasum": ""
},
"require": {
@@ -3142,7 +3148,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.11-dev"
+ "dev-master": "1.12-dev"
}
},
"autoload": {
@@ -3176,7 +3182,7 @@
"portable",
"shim"
],
- "time": "2019-02-06T07:57:58+00:00"
+ "time": "2019-08-06T08:03:45+00:00"
},
{
"name": "symfony/process",
@@ -3349,16 +3355,16 @@
},
{
"name": "theseer/tokenizer",
- "version": "1.1.2",
+ "version": "1.1.3",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
- "reference": "1c42705be2b6c1de5904f8afacef5895cab44bf8"
+ "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/1c42705be2b6c1de5904f8afacef5895cab44bf8",
- "reference": "1c42705be2b6c1de5904f8afacef5895cab44bf8",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
+ "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
"shasum": ""
},
"require": {
@@ -3385,20 +3391,20 @@
}
],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
- "time": "2019-04-04T09:56:43+00:00"
+ "time": "2019-06-13T22:48:21+00:00"
},
{
"name": "webmozart/assert",
- "version": "1.4.0",
+ "version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
- "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9"
+ "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9",
- "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9",
+ "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4",
+ "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4",
"shasum": ""
},
"require": {
@@ -3406,8 +3412,7 @@
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
- "phpunit/phpunit": "^4.6",
- "sebastian/version": "^1.0.1"
+ "phpunit/phpunit": "^4.8.36 || ^7.5.13"
},
"type": "library",
"extra": {
@@ -3436,12 +3441,21 @@
"check",
"validate"
],
- "time": "2018-12-25T11:19:39+00:00"
+ "time": "2019-08-24T08:43:50+00:00"
+ }
+ ],
+ "aliases": [
+ {
+ "alias": "1.x-dev",
+ "alias_normalized": "1.9999999.9999999.9999999-dev",
+ "version": "dev-local",
+ "package": "instaclick/php-webdriver"
}
],
- "aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {
+ "instaclick/php-webdriver": 20
+ },
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
diff --git a/config-dist.php b/config-dist.php
index 5f4258a3b1644..5a9df8d92b32c 100644
--- a/config-dist.php
+++ b/config-dist.php
@@ -543,7 +543,7 @@
//
// Location for lock files used by the File locking factory. This must exist
// on a shared file system that supports locking.
-// $CFG->lock_file_root = $CFG->dataroot . '/lock';
+// $CFG->file_lock_root = $CFG->dataroot . '/lock';
//
//
// Alternative task logging.
@@ -834,6 +834,10 @@
// Example:
// $CFG->behat_faildump_path = '/my/path/to/save/failure/dumps';
//
+// You can make behat pause upon failure to help you diagnose and debug problems with your tests.
+//
+// $CFG->behat_pause_on_fail = true;
+//
// You can specify db, selenium wd_host etc. for behat parallel run by setting following variable.
// Example:
// $CFG->behat_parallel_run = array (
diff --git a/course/amd/build/repository.min.js b/course/amd/build/repository.min.js
index 5ea972f7cb2e7..f4d899c121371 100644
--- a/course/amd/build/repository.min.js
+++ b/course/amd/build/repository.min.js
@@ -1 +1 @@
-define(["jquery","core/ajax"],function(a,b){var c=function(a,c,d,e){var f={classification:a};"undefined"!=typeof c&&(f.limit=c),"undefined"!=typeof d&&(f.offset=d),"undefined"!=typeof e&&(f.sort=e);var g={methodname:"core_course_get_enrolled_courses_by_timeline_classification",args:f};return b.call([g])[0]},d=function(a,c,d,e){var f={};"undefined"!=typeof a&&(f.limit=c),"undefined"!=typeof c&&(f.limit=c),"undefined"!=typeof d&&(f.offset=d),"undefined"!=typeof e&&(f.sort=e);var g={methodname:"core_course_get_recent_courses",args:f};return b.call([g])[0]};return{getEnrolledCoursesByTimelineClassification:c,getLastAccessedCourses:d}});
\ No newline at end of file
+define(["jquery","core/ajax"],function(a,b){var c=function(a,c,d,e){var f={classification:a};"undefined"!=typeof c&&(f.limit=c),"undefined"!=typeof d&&(f.offset=d),"undefined"!=typeof e&&(f.sort=e);var g={methodname:"core_course_get_enrolled_courses_by_timeline_classification",args:f};return b.call([g])[0]},d=function(a,c,d,e){var f={};"undefined"!=typeof a&&(f.userid=a),"undefined"!=typeof c&&(f.limit=c),"undefined"!=typeof d&&(f.offset=d),"undefined"!=typeof e&&(f.sort=e);var g={methodname:"core_course_get_recent_courses",args:f};return b.call([g])[0]};return{getEnrolledCoursesByTimelineClassification:c,getLastAccessedCourses:d}});
\ No newline at end of file
diff --git a/course/amd/src/repository.js b/course/amd/src/repository.js
index 98b67d5a24df1..6340eab31b125 100644
--- a/course/amd/src/repository.js
+++ b/course/amd/src/repository.js
@@ -71,7 +71,7 @@ define(['jquery', 'core/ajax'], function($, Ajax) {
var args = {};
if (typeof userid !== 'undefined') {
- args.limit = limit;
+ args.userid = userid;
}
if (typeof limit !== 'undefined') {
diff --git a/course/classes/analytics/indicator/activities_due.php b/course/classes/analytics/indicator/activities_due.php
index 425785173bce5..b87da32734f71 100644
--- a/course/classes/analytics/indicator/activities_due.php
+++ b/course/classes/analytics/indicator/activities_due.php
@@ -68,8 +68,10 @@ public static function required_sample_data() {
*/
protected function calculate_sample($sampleid, $sampleorigin, $starttime = false, $endtime = false) {
+ $user = $this->retrieve('user', $sampleid);
+
$actionevents = \core_calendar_external::get_calendar_action_events_by_timesort($starttime, $endtime, 0, 1,
- true, $sampleid);
+ true, $user->id);
if ($actionevents->events) {
diff --git a/course/classes/analytics/target/course_enrolments.php b/course/classes/analytics/target/course_enrolments.php
index e97112a4172bc..f5321928e5b83 100644
--- a/course/classes/analytics/target/course_enrolments.php
+++ b/course/classes/analytics/target/course_enrolments.php
@@ -74,6 +74,10 @@ public function is_valid_analysable(\core_analytics\analysable $course, $fortrai
return get_string('coursenotyetstarted', 'course');
}
+ if (!$fortraining && !$course->get_course_data()->visible) {
+ return get_string('hiddenfromstudents');
+ }
+
if (!$this->students = $course->get_students()) {
return get_string('nocoursestudents', 'course');
}
@@ -122,6 +126,8 @@ public function is_valid_analysable(\core_analytics\analysable $course, $fortrai
*/
public function is_valid_sample($sampleid, \core_analytics\analysable $course, $fortraining = true) {
+ $now = time();
+
$userenrol = $this->retrieve('user_enrolments', $sampleid);
if ($userenrol->timeend && $course->get_start() > $userenrol->timeend) {
// Discard enrolments which time end is prior to the course start. This should get rid of
@@ -139,9 +145,22 @@ public function is_valid_sample($sampleid, \core_analytics\analysable $course, $
return false;
}
- if (($userenrol->timestart && $userenrol->timestart > $course->get_end()) ||
- (!$userenrol->timestart && $userenrol->timecreated > $course->get_end())) {
- // Discard user enrolments that starts after the analysable official end.
+ if ($course->get_end()) {
+ if (($userenrol->timestart && $userenrol->timestart > $course->get_end()) ||
+ (!$userenrol->timestart && $userenrol->timecreated > $course->get_end())) {
+ // Discard user enrolments that starts after the analysable official end.
+ return false;
+ }
+
+ }
+
+ if ($now < $userenrol->timestart && $userenrol->timestart) {
+ // Discard enrolments whose start date is after now (no need to check timecreated > $now :P).
+ return false;
+ }
+
+ if (!$fortraining && $userenrol->timeend && $userenrol->timeend < $now) {
+ // We don't want to generate predictions for finished enrolments.
return false;
}
diff --git a/course/classes/category.php b/course/classes/category.php
index 251c460823ef1..b6aef77814532 100644
--- a/course/classes/category.php
+++ b/course/classes/category.php
@@ -717,13 +717,49 @@ public function get_db_record() {
* @return mixed
*/
protected static function get_tree($id) {
- global $DB;
$coursecattreecache = cache::make('core', 'coursecattree');
$rv = $coursecattreecache->get($id);
if ($rv !== false) {
return $rv;
}
+ // Might need to rebuild the tree. Put a lock in place to ensure other requests don't try and do this in parallel.
+ $lockfactory = \core\lock\lock_config::get_lock_factory('core_coursecattree');
+ $lock = $lockfactory->get_lock('core_coursecattree_cache',
+ course_modinfo::COURSE_CACHE_LOCK_WAIT, course_modinfo::COURSE_CACHE_LOCK_EXPIRY);
+ if ($lock === false) {
+ // Couldn't get a lock to rebuild the tree.
+ return [];
+ }
+ $rv = $coursecattreecache->get($id);
+ if ($rv !== false) {
+ // Tree was built while we were waiting for the lock.
+ $lock->release();
+ return $rv;
+ }
// Re-build the tree.
+ try {
+ $all = self::rebuild_coursecattree_cache_contents();
+ $coursecattreecache->set_many($all);
+ } finally {
+ $lock->release();
+ }
+ if (array_key_exists($id, $all)) {
+ return $all[$id];
+ }
+ // Requested non-existing category.
+ return array();
+ }
+
+ /**
+ * Rebuild the course category tree as an array, including an extra "countall" field.
+ *
+ * @return array
+ * @throws coding_exception
+ * @throws dml_exception
+ * @throws moodle_exception
+ */
+ private static function rebuild_coursecattree_cache_contents() : array {
+ global $DB;
$sql = "SELECT cc.id, cc.parent, cc.visible
FROM {course_categories} cc
ORDER BY cc.sortorder";
@@ -760,12 +796,7 @@ protected static function get_tree($id) {
}
// We must add countall to all in case it was the requested ID.
$all['countall'] = $count;
- $coursecattreecache->set_many($all);
- if (array_key_exists($id, $all)) {
- return $all[$id];
- }
- // Requested non-existing category.
- return array();
+ return $all;
}
/**
diff --git a/course/classes/customfield/course_handler.php b/course/classes/customfield/course_handler.php
index d7badc85bf768..dede44dcbb960 100644
--- a/course/classes/customfield/course_handler.php
+++ b/course/classes/customfield/course_handler.php
@@ -68,6 +68,17 @@ public static function create(int $itemid = 0) : \core_customfield\handler {
return self::$singleton;
}
+ /**
+ * Run reset code after unit tests to reset the singleton usage.
+ */
+ public static function reset_caches(): void {
+ if (!PHPUNIT_TEST) {
+ throw new \coding_exception('This feature is only intended for use in unit tests');
+ }
+
+ static::$singleton = null;
+ }
+
/**
* The current user can configure custom fields on this component.
*
diff --git a/course/classes/external/course_summary_exporter.php b/course/classes/external/course_summary_exporter.php
index 566af235f793e..65471f7298d34 100644
--- a/course/classes/external/course_summary_exporter.php
+++ b/course/classes/external/course_summary_exporter.php
@@ -105,6 +105,9 @@ public static function define_properties() {
),
'enddate' => array(
'type' => PARAM_INT,
+ ),
+ 'visible' => array(
+ 'type' => PARAM_BOOL,
)
);
}
diff --git a/course/edit.php b/course/edit.php
index 81626d8f87ae3..87c277a161a75 100644
--- a/course/edit.php
+++ b/course/edit.php
@@ -166,6 +166,8 @@
if (!empty($CFG->creatornewroleid) and !is_viewing($context, NULL, 'moodle/role:assign') and !is_enrolled($context, NULL, 'moodle/role:assign')) {
// Deal with course creators - enrol them internally with default role.
+ // Note: This does not respect capabilities, the creator will be assigned the default role.
+ // This is an expected behaviour. See MDL-66683 for further details.
enrol_try_internal_enrol($course->id, $USER->id, $CFG->creatornewroleid);
}
diff --git a/course/editsection.php b/course/editsection.php
index b04440bf8fe11..04ece14bf12b5 100644
--- a/course/editsection.php
+++ b/course/editsection.php
@@ -84,7 +84,14 @@
}
}
-$editoroptions = array('context'=>$context ,'maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes'=>$CFG->maxbytes, 'trusttext'=>false, 'noclean'=>true);
+$editoroptions = array(
+ 'context' => $context,
+ 'maxfiles' => EDITOR_UNLIMITED_FILES,
+ 'maxbytes' => $CFG->maxbytes,
+ 'trusttext' => false,
+ 'noclean' => true,
+ 'subdirs' => true
+);
$courseformat = course_get_format($course);
$defaultsectionname = $courseformat->get_default_section_name($section);
diff --git a/course/externallib.php b/course/externallib.php
index bd4426082a516..23123acf9b470 100644
--- a/course/externallib.php
+++ b/course/externallib.php
@@ -3716,7 +3716,7 @@ public static function get_module($id, $sectionreturn = null) {
}
/**
- * Return structure for edit_module()
+ * Return structure for get_module()
*
* @since Moodle 3.3
* @return external_description
diff --git a/course/format/renderer.php b/course/format/renderer.php
index 2f94041f73484..b033633a73f56 100644
--- a/course/format/renderer.php
+++ b/course/format/renderer.php
@@ -488,11 +488,6 @@ protected function section_activity_summary($section, $course, $mods) {
foreach ($modinfo->sections[$section->section] as $cmid) {
$thismod = $modinfo->cms[$cmid];
- if ($thismod->modname == 'label') {
- // Labels are special (not interesting for students)!
- continue;
- }
-
if ($thismod->uservisible) {
if (isset($sectionmods[$thismod->modname])) {
$sectionmods[$thismod->modname]['name'] = $thismod->modplural;
@@ -519,7 +514,7 @@ protected function section_activity_summary($section, $course, $mods) {
// Output section activities summary:
$o = '';
- $o.= html_writer::start_tag('div', array('class' => 'section-summary-activities mdl-right'));
+ $o.= html_writer::start_tag('div', array('class' => 'section-summary-activities pr-2 mdl-right'));
foreach ($sectionmods as $mod) {
$o.= html_writer::start_tag('span', array('class' => 'activity-count'));
$o.= $mod['name'].': '.$mod['count'];
@@ -533,7 +528,7 @@ protected function section_activity_summary($section, $course, $mods) {
$a->complete = $complete;
$a->total = $total;
- $o.= html_writer::start_tag('div', array('class' => 'section-summary-activities mdl-right'));
+ $o.= html_writer::start_tag('div', array('class' => 'section-summary-activities pr-2 mdl-right'));
$o.= html_writer::tag('span', get_string('progresstotal', 'completion', $a), array('class' => 'activity-count'));
$o.= html_writer::end_tag('div');
}
diff --git a/course/format/singleactivity/lib.php b/course/format/singleactivity/lib.php
index 50fa91a7f20a9..5db9dea89ea63 100644
--- a/course/format/singleactivity/lib.php
+++ b/course/format/singleactivity/lib.php
@@ -36,6 +36,9 @@ class format_singleactivity extends format_base {
/** @var cm_info the current activity. Use get_activity() to retrieve it. */
private $activity = false;
+ /** @var int The category ID guessed from the form data. */
+ private $categoryid = false;
+
/**
* The URL to use for the specified course
*
@@ -145,6 +148,30 @@ public function get_default_blocks() {
*/
public function course_format_options($foreditform = false) {
static $courseformatoptions = false;
+
+ $fetchtypes = $courseformatoptions === false;
+ $fetchtypes = $fetchtypes || ($foreditform && !isset($courseformatoptions['activitytype']['label']));
+
+ if ($fetchtypes) {
+ $availabletypes = $this->get_supported_activities();
+ if ($this->course) {
+ // The course exists. Test against the course.
+ $testcontext = context_course::instance($this->course->id);
+ } else if ($this->categoryid) {
+ // The course does not exist yet, but we have a category ID that we can test against.
+ $testcontext = context_coursecat::instance($this->categoryid);
+ } else {
+ // The course does not exist, and we somehow do not have a category. Test capabilities against the system context.
+ $testcontext = context_system::instance();
+ }
+ foreach (array_keys($availabletypes) as $activity) {
+ $capability = "mod/{$activity}:addinstance";
+ if (!has_capability($capability, $testcontext)) {
+ unset($availabletypes[$activity]);
+ }
+ }
+ }
+
if ($courseformatoptions === false) {
$config = get_config('format_singleactivity');
$courseformatoptions = array(
@@ -153,9 +180,13 @@ public function course_format_options($foreditform = false) {
'type' => PARAM_TEXT,
),
);
+
+ if (!empty($availabletypes) && !isset($availabletypes[$config->activitytype])) {
+ $courseformatoptions['activitytype']['default'] = array_keys($availabletypes)[0];
+ }
}
+
if ($foreditform && !isset($courseformatoptions['activitytype']['label'])) {
- $availabletypes = $this->get_supported_activities();
$courseformatoptionsedit = array(
'activitytype' => array(
'label' => new lang_string('activitytype', 'format_singleactivity'),
@@ -183,6 +214,11 @@ public function course_format_options($foreditform = false) {
*/
public function create_edit_form_elements(&$mform, $forsection = false) {
global $PAGE;
+
+ if (!$this->course && $submitvalues = $mform->getSubmitValues()) {
+ $this->categoryid = $submitvalues['category'];
+ }
+
$elements = parent::create_edit_form_elements($mform, $forsection);
if (!$forsection && ($course = $PAGE->course) && !empty($course->format) &&
$course->format !== 'site' && $course->format !== 'singleactivity') {
diff --git a/course/format/singleactivity/tests/behat/create_course.feature b/course/format/singleactivity/tests/behat/create_course.feature
new file mode 100644
index 0000000000000..6eee07ff1cf6c
--- /dev/null
+++ b/course/format/singleactivity/tests/behat/create_course.feature
@@ -0,0 +1,38 @@
+@format @format_singleactivity
+Feature: Courses can be created in Single Activity mode
+ In order to create a single activity course
+ As a manager
+ I need to create courses and set default values on them
+
+ Scenario: Create a course as a custom course creator
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | kevin | Kevin | the | kevin@example.com |
+ And the following "roles" exist:
+ | shortname | name | archetype |
+ | creator | Creator | |
+ And the following "system role assigns" exist:
+ | user | role | contextlevel |
+ | kevin | creator | System |
+ And I log in as "admin"
+ And I set the following system permissions of "Creator" role:
+ | capability | permission |
+ | moodle/course:create | Allow |
+ | moodle/course:update | Allow |
+ | moodle/course:manageactivities | Allow |
+ | moodle/course:viewparticipants | Allow |
+ | moodle/role:assign | Allow |
+ | mod/quiz:addinstance | Allow |
+ And I log out
+ And I log in as "kevin"
+ And I am on site homepage
+ When I press "Add a new course"
+ And I set the following fields to these values:
+ | Course full name | My first course |
+ | Course short name | myfirstcourse |
+ | Format | Single activity format |
+ And I press "Update format"
+ Then I should see "Quiz" in the "Type of activity" "field"
+ And I should not see "Forum" in the "Type of activity" "field"
+ And I press "Save and display"
+ And I should see "Adding a new Quiz"
diff --git a/course/format/social/format.php b/course/format/social/format.php
index bde9709102155..44cf6ca12ab4a 100644
--- a/course/format/social/format.php
+++ b/course/format/social/format.php
@@ -50,7 +50,7 @@
$streditsummary = get_string('editsummary');
$introcontent .= html_writer::start_div('editinglink');
$introcontent .= html_writer::link(
- new moodle_url('/modedit.php', [
+ new moodle_url('/course/modedit.php', [
'update' => $coursemodule->id,
'sesskey' => sesskey(),
]),
diff --git a/course/format/topics/db/upgrade.php b/course/format/topics/db/upgrade.php
index 055a902bca658..6dc38410cc8aa 100644
--- a/course/format/topics/db/upgrade.php
+++ b/course/format/topics/db/upgrade.php
@@ -65,5 +65,8 @@ function xmldb_format_topics_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/course/format/weeks/db/upgrade.php b/course/format/weeks/db/upgrade.php
index bbb141f28c58d..0309ac8001418 100644
--- a/course/format/weeks/db/upgrade.php
+++ b/course/format/weeks/db/upgrade.php
@@ -101,5 +101,8 @@ function xmldb_format_weeks_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/course/lib.php b/course/lib.php
index 25af452c7fab7..1094eb8aa4440 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1144,7 +1144,9 @@ function course_delete_module($cmid, $async = false) {
}
// Delete activity context questions and question categories.
- question_delete_activity($cm);
+ $showinfo = !defined('AJAX_SCRIPT') || AJAX_SCRIPT == '0';
+
+ question_delete_activity($cm, $showinfo);
// Call the delete_instance function, if it returns false throw an exception.
if (!$deleteinstancefunction($cm->instance)) {
@@ -1289,16 +1291,36 @@ function course_module_flag_for_async_deletion($cmid) {
* Checks whether the given course has any course modules scheduled for adhoc deletion.
*
* @param int $courseid the id of the course.
+ * @param bool $onlygradable whether to check only gradable modules or all modules.
* @return bool true if the course contains any modules pending deletion, false otherwise.
*/
-function course_modules_pending_deletion($courseid) {
+function course_modules_pending_deletion($courseid, bool $onlygradable = false) : bool {
if (empty($courseid)) {
return false;
}
+
+ if ($onlygradable) {
+ // Fetch modules with grade items.
+ if (!$coursegradeitems = grade_item::fetch_all(['itemtype' => 'mod', 'courseid' => $courseid])) {
+ // Return early when there is none.
+ return false;
+ }
+ }
+
$modinfo = get_fast_modinfo($courseid);
foreach ($modinfo->get_cms() as $module) {
if ($module->deletioninprogress == '1') {
- return true;
+ if ($onlygradable) {
+ // Check if the module being deleted is in the list of course modules with grade items.
+ foreach ($coursegradeitems as $coursegradeitem) {
+ if ($coursegradeitem->itemmodule == $module->modname && $coursegradeitem->iteminstance == $module->instance) {
+ // The module being deleted is within the gradable modules.
+ return true;
+ }
+ }
+ } else {
+ return true;
+ }
}
}
return false;
@@ -2182,6 +2204,7 @@ function move_courses($courseids, $categoryid) {
foreach ($dbcourses as $dbcourse) {
$course = new stdClass();
$course->id = $dbcourse->id;
+ $course->timemodified = time();
$course->category = $category->id;
$course->sortorder = $category->sortorder + MAX_COURSES_IN_CATEGORY - $i++;
if ($category->visible == 0) {
@@ -3994,7 +4017,6 @@ function course_get_user_administration_options($course, $context) {
$options->outcomes = !empty($CFG->enableoutcomes) && has_capability('moodle/course:update', $context);
$options->badges = !empty($CFG->enablebadges);
$options->import = has_capability('moodle/restore:restoretargetimport', $context);
- $options->publish = !empty($CFG->enablecoursepublishing) && has_capability('moodle/course:publish', $context);
$options->reset = has_capability('moodle/course:reset', $context);
$options->roles = has_capability('moodle/role:switchroles', $context);
} else {
@@ -4571,7 +4593,7 @@ function course_get_recent_courses(int $userid = null, int $limit = 0, int $offs
}
$basefields = array('id', 'idnumber', 'summary', 'summaryformat', 'startdate', 'enddate', 'category',
- 'shortname', 'fullname', 'timeaccess', 'component');
+ 'shortname', 'fullname', 'timeaccess', 'component', 'visible');
$sort = trim($sort);
if (empty($sort)) {
diff --git a/course/management.php b/course/management.php
index 27784d152afdc..ad74a3e2f3b3d 100644
--- a/course/management.php
+++ b/course/management.php
@@ -69,8 +69,11 @@
$course = null;
$courseid = null;
$topchildren = core_course_category::top()->get_children();
+ if (empty($topchildren)) {
+ throw new moodle_exception('cannotviewcategory', 'error');
+ }
$category = reset($topchildren);
- $categoryid = $category ? $category->id : 0;
+ $categoryid = $category->id;
$context = context_coursecat::instance($category->id);
$url->param('categoryid', $category->id);
}
@@ -313,7 +316,8 @@
$notificationsfail[] = get_string('movecategoryownparent', 'error', $cattomove->get_formatted_name());
continue;
}
- if (strpos($movetocat->path, $cattomove->path) === 0) {
+ // Don't allow user to move selected category into one of it's own sub-categories.
+ if (strpos($movetocat->path, $cattomove->path . '/') === 0) {
$notificationsfail[] = get_string('movecategoryparentconflict', 'error', $cattomove->get_formatted_name());
continue;
}
diff --git a/course/publish/backup.php b/course/publish/backup.php
deleted file mode 100644
index f9f9d7a7ab005..0000000000000
--- a/course/publish/backup.php
+++ /dev/null
@@ -1,113 +0,0 @@
-. //
-// //
-///////////////////////////////////////////////////////////////////////////
-
-/**
- * This page display the publication backup form
- *
- * @package course
- * @subpackage publish
- * @author Jerome Mouneyrac
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL
- * @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
- */
-
-define('NO_OUTPUT_BUFFERING', true);
-
-require_once('../../config.php');
-require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
-require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
-require_once($CFG->libdir . '/filelib.php');
-
-
-//retrieve initial page parameters
-$id = required_param('id', PARAM_INT);
-$hubcourseid = required_param('hubcourseid', PARAM_INT);
-
-//some permissions and parameters checking
-$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST);
-require_login($course);
-
-$context = context_course::instance($course->id);
-if (empty($CFG->enablecoursepublishing) || !has_capability('moodle/course:publish', $context) || !confirm_sesskey()) {
- throw new moodle_exception('nopermission');
-}
-
-//page settings
-$PAGE->set_url('/course/publish/backup.php');
-$PAGE->set_pagelayout('incourse');
-$PAGE->set_title(get_string('course') . ': ' . $course->fullname);
-$PAGE->set_heading($course->fullname);
-
-//BEGIN backup processing
-$backupid = optional_param('backup', false, PARAM_ALPHANUM);
-if (!($bc = backup_ui::load_controller($backupid))) {
- $bc = new backup_controller(backup::TYPE_1COURSE, $id, backup::FORMAT_MOODLE,
- backup::INTERACTIVE_YES, backup::MODE_HUB, $USER->id);
-}
-$backup = new backup_ui($bc,
- array('id' => $id, 'hubcourseid' => $hubcourseid, 'huburl' => HUB_MOODLEORGHUBURL, 'hubname' => 'Moodle.net'));
-$backup->process();
-if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
- $backup->execute();
-} else {
- $backup->save_controller();
-}
-
-if ($backup->get_stage() !== backup_ui::STAGE_COMPLETE) {
- $renderer = $PAGE->get_renderer('core', 'backup');
- echo $OUTPUT->header();
- echo $OUTPUT->heading(get_string('publishcourseon', 'hub', 'Moodle.net'), 3, 'main');
- if ($backup->enforce_changed_dependencies()) {
- debugging('Your settings have been altered due to unmet dependencies', DEBUG_DEVELOPER);
- }
- echo $renderer->progress_bar($backup->get_progress_bar());
- echo $backup->display($renderer);
- echo $OUTPUT->footer();
- die();
-}
-
-//$backupfile = $backup->get_stage_results();
-$backupfile = $bc->get_results();
-$backupfile = $backupfile['backup_destination'];
-//END backup processing
-
-//display the sending file page
-echo $OUTPUT->header();
-echo $OUTPUT->heading(get_string('sendingcourse', 'hub'), 3, 'main');
-$renderer = $PAGE->get_renderer('core', 'course');
-echo $renderer->sendingbackupinfo($backupfile);
-if (ob_get_level()) {
- ob_flush();
-}
-flush();
-
-//send backup file to the hub
-\core\hub\publication::upload_course_backup($hubcourseid, $backupfile);
-
-//delete the temp backup file from user_tohub aera
-$backupfile->delete();
-$bc->destroy();
-
-//Output sending success
-echo $renderer->sentbackupinfo($id, HUB_MOODLEORGHUBURL, 'Moodle.net');
-
-echo $OUTPUT->footer();
diff --git a/course/publish/forms.php b/course/publish/forms.php
deleted file mode 100644
index 288475e0aae0b..0000000000000
--- a/course/publish/forms.php
+++ /dev/null
@@ -1,36 +0,0 @@
-. //
-// //
-///////////////////////////////////////////////////////////////////////////
-
-/**
- * @package course
- * @subpackage publish
- * @author Jerome Mouneyrac
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL
- * @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
- *
- * The forms used for course publication
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-debugging('Support for alternative hubs has been removed from Moodle in 3.4. For communication with moodle.net ' .
- 'see lib/classes/hub/ .', DEBUG_DEVELOPER);
diff --git a/course/publish/index.php b/course/publish/index.php
deleted file mode 100644
index 7bff4732681ff..0000000000000
--- a/course/publish/index.php
+++ /dev/null
@@ -1,99 +0,0 @@
-.
-
-/*
- * @package course
- * @subpackage publish
- * @author Jerome Mouneyrac
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL
- * @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
- *
- * The user selects if he wants to publish the course on Moodle.org hub or
- * on a specific hub. The site must be registered on a hub to be able to
- * publish a course on it.
-*/
-
-require('../../config.php');
-
-$courseid = required_param('id', PARAM_INT); // Course id.
-$publicationid = optional_param('publicationid', 0, PARAM_INT); // Id of course publication to unpublish.
-
-require_login($courseid);
-$shortname = format_string($COURSE->shortname);
-
-$PAGE->set_url('/course/publish/index.php', array('id' => $courseid));
-$PAGE->set_pagelayout('incourse');
-$PAGE->set_title(get_string('publish', 'core_hub') . ': ' . $COURSE->fullname);
-$PAGE->set_heading($COURSE->fullname);
-
-$context = context_course::instance($courseid);
-if (empty($CFG->enablecoursepublishing) || !has_capability('moodle/course:publish', $context)) {
- throw new moodle_exception('nopermission');
-}
-
-// If the site is not registered display an error page.
-if (!\core\hub\registration::is_registered()) {
- echo $OUTPUT->header();
- echo $OUTPUT->heading(get_string('publishcourseon', 'hub', 'Moodle.net'), 3, 'main');
- echo $OUTPUT->box(get_string('notregisteredonhub', 'hub'));
- if (has_capability('moodle/site:config', context_system::instance())) {
- echo $OUTPUT->single_button(new moodle_url('/admin/registration/index.php'), get_string('register', 'admin'));
- }
- echo $OUTPUT->footer();
- die();
-}
-
-// When hub listing status is requested update statuses of all published courses.
-$updatestatusid = optional_param('updatestatusid', false, PARAM_INT);
-if (!empty($updatestatusid) && confirm_sesskey()) {
- if (core\hub\publication::get_publication($updatestatusid, $courseid)) {
- core\hub\publication::request_status_update();
- redirect($PAGE->url);
- }
-}
-
-$renderer = $PAGE->get_renderer('core', 'course');
-
-// Unpublish course.
-if ($publication = \core\hub\publication::get_publication($publicationid, $courseid)) {
- $confirm = optional_param('confirm', 0, PARAM_BOOL);
- if ($confirm && confirm_sesskey()) {
- \core\hub\publication::unpublish($publication);
- } else {
- // Display confirmation page for unpublishing.
- $publication = \core\hub\publication::get_publication($publicationid, $courseid, MUST_EXIST);
- $publication->courseshortname = format_string($COURSE->shortname);
- echo $OUTPUT->header();
- echo $OUTPUT->heading(get_string('unpublishcourse', 'hub', $shortname), 3, 'main');
- echo $renderer->confirmunpublishing($publication);
- echo $OUTPUT->footer();
- die();
- }
-}
-
-// List current publications and "Publish" buttons.
-echo $OUTPUT->header();
-
-echo $OUTPUT->heading(get_string('publishcourse', 'hub', $shortname), 3, 'main');
-echo $renderer->publicationselector($courseid);
-
-$publications = \core\hub\publication::get_course_publications($courseid);
-if (!empty($publications)) {
- echo $OUTPUT->heading(get_string('publishedon', 'hub'), 3, 'main');
- echo $renderer->registeredonhublisting($courseid, $publications);
-}
-
-echo $OUTPUT->footer();
diff --git a/course/publish/metadata.php b/course/publish/metadata.php
deleted file mode 100644
index 3042864d8b6ab..0000000000000
--- a/course/publish/metadata.php
+++ /dev/null
@@ -1,192 +0,0 @@
-. //
-// //
-///////////////////////////////////////////////////////////////////////////
-
-/*
- * @package course
- * @subpackage publish
- * @author Jerome Mouneyrac
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL
- * @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
- *
- * This page display the publication metadata form
- */
-
-require_once('../../config.php');
-require_once($CFG->libdir . '/filelib.php');
-
-
-//check user access capability to this page
-$id = required_param('id', PARAM_INT);
-
-$course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST);
-require_login($course);
-
-//page settings
-$PAGE->set_url('/course/publish/metadata.php', array('id' => $course->id));
-$PAGE->set_pagelayout('incourse');
-$PAGE->set_title(get_string('course') . ': ' . $course->fullname);
-$PAGE->set_heading($course->fullname);
-
-$context = context_course::instance($course->id);
-if (empty($CFG->enablecoursepublishing) || !has_capability('moodle/course:publish', $context)) {
- throw new moodle_exception('nopermission');
-}
-
-// Retrieve hub name and hub url.
-require_sesskey();
-
-// Set the publication form.
-$advertise = optional_param('advertise', false, PARAM_BOOL);
-$publicationid = optional_param('publicationid', false, PARAM_INT);
-$formparams = array('course' => $course, 'advertise' => $advertise);
-if ($publicationid) {
- $publication = \core\hub\publication::get_publication($publicationid, $course->id, MUST_EXIST);
- $formparams['publication'] = $publication;
- $advertise = $formparams['advertise'] = $publication->enrollable;
-}
-$share = !$advertise;
-$coursepublicationform = new \core\hub\course_publication_form('', $formparams);
-$fromform = $coursepublicationform->get_data();
-
-if (!empty($fromform)) {
-
- // Retrieve the course information.
- $courseinfo = new stdClass();
- $courseinfo->fullname = $fromform->name;
- $courseinfo->shortname = $fromform->courseshortname;
- $courseinfo->description = $fromform->description;
- $courseinfo->language = $fromform->language;
- $courseinfo->publishername = $fromform->publishername;
- $courseinfo->publisheremail = $fromform->publisheremail;
- $courseinfo->contributornames = $fromform->contributornames;
- $courseinfo->coverage = $fromform->coverage;
- $courseinfo->creatorname = $fromform->creatorname;
- $courseinfo->licenceshortname = $fromform->licence;
- $courseinfo->subject = $fromform->subject;
- $courseinfo->audience = $fromform->audience;
- $courseinfo->educationallevel = $fromform->educationallevel;
- $creatornotes = $fromform->creatornotes;
- $courseinfo->creatornotes = $creatornotes['text'];
- $courseinfo->creatornotesformat = $creatornotes['format'];
- $courseinfo->sitecourseid = $id;
- if (!empty($fromform->deletescreenshots)) {
- $courseinfo->deletescreenshots = $fromform->deletescreenshots;
- }
- if ($share) {
- $courseinfo->demourl = $fromform->demourl;
- $courseinfo->enrollable = false;
- } else {
- $courseinfo->courseurl = $fromform->courseurl;
- $courseinfo->enrollable = true;
- }
-
- // Retrieve the outcomes of this course.
- require_once($CFG->libdir . '/grade/grade_outcome.php');
- $outcomes = grade_outcome::fetch_all_available($id);
- if (!empty($outcomes)) {
- foreach ($outcomes as $outcome) {
- $sentoutcome = new stdClass();
- $sentoutcome->fullname = $outcome->fullname;
- $courseinfo->outcomes[] = $sentoutcome;
- }
- }
-
- // Retrieve the content information from the course.
- $coursecontext = context_course::instance($course->id);
- $courseblocks = \core\hub\publication::get_block_instances_by_context($coursecontext->id);
-
- if (!empty($courseblocks)) {
- $blockname = '';
- foreach ($courseblocks as $courseblock) {
- if ($courseblock->blockname != $blockname) {
- if (!empty($blockname)) {
- $courseinfo->contents[] = $content;
- }
-
- $blockname = $courseblock->blockname;
- $content = new stdClass();
- $content->moduletype = 'block';
- $content->modulename = $courseblock->blockname;
- $content->contentcount = 1;
- } else {
- $content->contentcount = $content->contentcount + 1;
- }
- }
- $courseinfo->contents[] = $content;
- }
-
- $activities = get_fast_modinfo($course, $USER->id);
- foreach ($activities->instances as $activityname => $activitydetails) {
- $content = new stdClass();
- $content->moduletype = 'activity';
- $content->modulename = $activityname;
- $content->contentcount = count($activities->instances[$activityname]);
- $courseinfo->contents[] = $content;
- }
-
- // Save into screenshots field the references to the screenshot content hash
- // (it will be like a unique id from the hub perspective).
- if (!empty($fromform->deletescreenshots) or $share) {
- $courseinfo->screenshots = 0;
- } else {
- $courseinfo->screenshots = $fromform->existingscreenshotnumber;
- }
- $files = [];
- if (!empty($fromform->screenshots)) {
- $fs = get_file_storage();
- $files = $fs->get_area_files(context_user::instance($USER->id)->id, 'user', 'draft', $fromform->screenshots,
- 'filepath, filename', false);
- $files = array_filter($files, function(stored_file $file) {
- return $file->is_valid_image();
- });
- $courseinfo->screenshots += count($files);
- }
-
- // PUBLISH ACTION.
- $hubcourseid = \core\hub\publication::publish_course($courseinfo, $files);
-
- // Redirect to the backup process page.
- if ($share) {
- $params = array('sesskey' => sesskey(), 'id' => $id, 'hubcourseid' => $hubcourseid);
- $backupprocessurl = new moodle_url("/course/publish/backup.php", $params);
- redirect($backupprocessurl);
- } else {
- // Redirect to the index publis page.
- redirect(new moodle_url('/course/publish/index.php', ['id' => $id]),
- get_string('coursepublished', 'hub', 'Moodle.net'), null, \core\output\notification::NOTIFY_SUCCESS);
- }
-}
-
-// OUTPUT SECTION.
-
-echo $OUTPUT->header();
-echo $OUTPUT->heading(get_string('publishcourseon', 'hub', 'Moodle.net'), 3, 'main');
-
-// Display hub information (logo, name, description).
-$renderer = $PAGE->get_renderer('core', 'course');
-if ($hubinfo = \core\hub\registration::get_moodlenet_info()) {
- echo $renderer->hubinfo($hubinfo);
-}
-
-// Display metadata form.
-$coursepublicationform->display();
-echo $OUTPUT->footer();
diff --git a/course/renderer.php b/course/renderer.php
index 9d1439c7ad8bc..30c865b19d0f4 100644
--- a/course/renderer.php
+++ b/course/renderer.php
@@ -2105,128 +2105,6 @@ public function render_activity_navigation(\core_course\output\activity_navigati
return $this->output->render_from_template('core_course/activity_navigation', $data);
}
- /**
- * Display the selector to advertise or publish a course
- * @param int $courseid
- */
- public function publicationselector($courseid) {
- $text = '';
-
- $advertiseurl = new moodle_url("/course/publish/metadata.php",
- array('sesskey' => sesskey(), 'id' => $courseid, 'advertise' => true));
- $advertisebutton = new single_button($advertiseurl, get_string('advertise', 'hub'));
- $text .= $this->output->render($advertisebutton);
- $text .= html_writer::tag('div', get_string('advertisepublication_help', 'hub'),
- array('class' => 'publishhelp'));
-
- $text .= html_writer::empty_tag('br'); // TODO Delete.
-
- $uploadurl = new moodle_url("/course/publish/metadata.php",
- array('sesskey' => sesskey(), 'id' => $courseid, 'share' => true));
- $uploadbutton = new single_button($uploadurl, get_string('share', 'hub'));
- $text .= $this->output->render($uploadbutton);
- $text .= html_writer::tag('div', get_string('sharepublication_help', 'hub'),
- array('class' => 'publishhelp'));
-
- return $text;
- }
-
- /**
- * Display the listing of hub where a course is registered on
- * @param int $courseid
- * @param array $publications
- */
- public function registeredonhublisting($courseid, $publications) {
- global $CFG;
- $table = new html_table();
- $table->head = array(get_string('type', 'hub'),
- get_string('date'), get_string('status', 'hub'), get_string('operation', 'hub'));
- $table->size = array('20%', '30%', '%20', '%25');
-
- $brtag = html_writer::empty_tag('br');
-
- foreach ($publications as $publication) {
-
- $params = array('id' => $publication->courseid, 'publicationid' => $publication->id);
- $cancelurl = new moodle_url("/course/publish/index.php", $params);
- $cancelbutton = new single_button($cancelurl, get_string('removefromhub', 'hub'));
- $cancelbutton->class = 'centeredbutton';
- $cancelbuttonhtml = $this->output->render($cancelbutton);
-
- if ($publication->enrollable) {
- $params = array('sesskey' => sesskey(), 'id' => $publication->courseid, 'publicationid' => $publication->id);
- $updateurl = new moodle_url("/course/publish/metadata.php", $params);
- $updatebutton = new single_button($updateurl, get_string('update', 'hub'));
- $updatebutton->class = 'centeredbutton';
- $updatebuttonhtml = $this->output->render($updatebutton);
-
- $operations = $updatebuttonhtml . $brtag . $cancelbuttonhtml;
- } else {
- $operations = $cancelbuttonhtml;
- }
-
- // If the publication check time if bigger than May 2010, it has been checked.
- if ($publication->timechecked > 1273127954) {
- if ($publication->status == 0) {
- $status = get_string('statusunpublished', 'hub');
- } else {
- $status = get_string('statuspublished', 'hub');
- if (!empty($publication->link)) {
- $status = html_writer::link($publication->link, $status);
- }
- }
-
- $status .= $brtag . html_writer::tag('a', get_string('updatestatus', 'hub'),
- array('href' => $CFG->wwwroot . '/course/publish/index.php?id='
- . $courseid . "&updatestatusid=" . $publication->id
- . "&sesskey=" . sesskey())) .
- $brtag . get_string('lasttimechecked', 'hub') . ": "
- . format_time(time() - $publication->timechecked);
- } else {
- $status = get_string('neverchecked', 'hub') . $brtag
- . html_writer::tag('a', get_string('updatestatus', 'hub'),
- array('href' => $CFG->wwwroot . '/course/publish/index.php?id='
- . $courseid . "&updatestatusid=" . $publication->id
- . "&sesskey=" . sesskey()));
- }
- // Add button cells.
- $cells = array($publication->enrollable ?
- get_string('advertised', 'hub') : get_string('shared', 'hub'),
- userdate($publication->timepublished,
- get_string('strftimedatetimeshort')), $status, $operations);
- $row = new html_table_row($cells);
- $table->data[] = $row;
- }
-
- $contenthtml = html_writer::table($table);
-
- return $contenthtml;
- }
-
- /**
- * Display unpublishing confirmation page
- * @param stdClass $publication
- * $publication->courseshortname
- * $publication->courseid
- * $publication->hubname
- * $publication->huburl
- * $publication->id
- */
- public function confirmunpublishing($publication) {
- $optionsyes = array('sesskey' => sesskey(), 'id' => $publication->courseid,
- 'hubcourseid' => $publication->hubcourseid,
- 'cancel' => true, 'publicationid' => $publication->id, 'confirm' => true);
- $optionsno = array('sesskey' => sesskey(), 'id' => $publication->courseid);
- $publication->hubname = html_writer::tag('a', 'Moodle.net',
- array('href' => HUB_MOODLEORGHUBURL));
- $formcontinue = new single_button(new moodle_url("/course/publish/index.php",
- $optionsyes), get_string('unpublish', 'hub'), 'post');
- $formcancel = new single_button(new moodle_url("/course/publish/index.php",
- $optionsno), get_string('cancel'), 'get');
- return $this->output->confirm(get_string('unpublishconfirmation', 'hub', $publication),
- $formcontinue, $formcancel);
- }
-
/**
* Display waiting information about backup size during uploading backup process
* @param object $backupfile the backup stored_file
@@ -2240,23 +2118,6 @@ public function sendingbackupinfo($backupfile) {
return $html;
}
- /**
- * Display upload successfull message and a button to the publish index page
- * @param int $id the course id
- * @return $html string
- */
- public function sentbackupinfo($id) {
- $html = html_writer::tag('div', get_string('sent', 'hub'),
- array('class' => 'courseuploadtextinfo'));
- $publishindexurl = new moodle_url('/course/publish/index.php',
- array('sesskey' => sesskey(), 'id' => $id,
- 'published' => true));
- $continue = $this->output->render(
- new single_button($publishindexurl, get_string('continue')));
- $html .= html_writer::tag('div', $continue, array('class' => 'sharecoursecontinue'));
- return $html;
- }
-
/**
* Hub information (logo - name - description - link)
* @param object $hubinfo
diff --git a/course/templates/activity_navigation.mustache b/course/templates/activity_navigation.mustache
index c3583e1900f03..3b2af237a6d83 100644
--- a/course/templates/activity_navigation.mustache
+++ b/course/templates/activity_navigation.mustache
@@ -64,7 +64,7 @@
}
}
}}
-
+
{{< core/columns-1to1to1}}
{{$column1}}
diff --git a/course/templates/coursecard.mustache b/course/templates/coursecard.mustache
index 1aba15c597fd7..74300b9fb6c9a 100644
--- a/course/templates/coursecard.mustache
+++ b/course/templates/coursecard.mustache
@@ -28,7 +28,8 @@
"courseimage": "https://moodlesite/pluginfile/123/course/overviewfiles/123.jpg",
"fullname": "course 3",
"hasprogress": true,
- "progress": 10
+ "progress": 10,
+ "visible": true
}
]
}
@@ -43,8 +44,8 @@
-
diff --git a/course/tests/behat/app_course_completion.feature b/course/tests/behat/app_course_completion.feature
deleted file mode 100644
index f0c30baa969d1..0000000000000
--- a/course/tests/behat/app_course_completion.feature
+++ /dev/null
@@ -1,36 +0,0 @@
-@core @core_course @app @javascript
-Feature: Check course completion feature.
- In order to track the progress of the course on mobile device
- As a student
- I need to be able to update the activity completion status.
-
- Background:
- Given the following "users" exist:
- | username | firstname | lastname | email |
- | student1 | Student | 1 | student1@example.com |
- And the following "courses" exist:
- | fullname | shortname | category | enablecompletion |
- | Course 1 | C1 | 0 | 1 |
- And the following "course enrolments" exist:
- | user | course | role |
- | student1 | C1 | student |
-
- Scenario: Complete the activity manually by clicking at the completion checkbox.
- Given the following "activities" exist:
- | activity | name | course | idnumber | completion | completionview |
- | forum | First forum | C1 | forum1 | 1 | 0 |
- | forum | Second forum | C1 | forum2 | 1 | 0 |
- When I enter the app
- And I log in as "student1"
- And I press "Course 1" near "Recently accessed courses" in the app
- # Set activities as completed.
- And I should see "0%"
- And I press "Not completed: First forum. Select to mark as complete." in the app
- And I should see "50%"
- And I press "Not completed: Second forum. Select to mark as complete." in the app
- And I should see "100%"
- # Set activities as not completed.
- And I press "Completed: First forum. Select to mark as not complete." in the app
- And I should see "50%"
- And I press "Completed: Second forum. Select to mark as not complete." in the app
- And I should see "0%"
diff --git a/course/tests/behat/app_courselist.feature b/course/tests/behat/app_courselist.feature
deleted file mode 100644
index ea68c0542eb95..0000000000000
--- a/course/tests/behat/app_courselist.feature
+++ /dev/null
@@ -1,120 +0,0 @@
-@core @core_course @app @javascript
-Feature: Test course list shown on app start tab
- In order to select a course
- As a student
- I need to see the correct list of courses
-
- Background:
- Given the following "courses" exist:
- | fullname | shortname |
- | Course 1 | C1 |
- | Course 2 | C2 |
- And the following "users" exist:
- | username |
- | student1 |
- | student2 |
- And the following "course enrolments" exist:
- | user | course | role |
- | student1 | C1 | student |
- | student2 | C1 | student |
- | student2 | C2 | student |
-
- Scenario: Student is registered on one course
- When I enter the app
- And I log in as "student1"
- Then I should see "Course 1"
- And I should not see "Course 2"
-
- Scenario: Student is registered on two courses (shortnames not displayed)
- When I enter the app
- And I log in as "student2"
- Then I should see "Course 1"
- And I should see "Course 2"
- And I should not see "C1"
- And I should not see "C2"
-
- Scenario: Student is registered on two courses (shortnames displayed)
- Given the following config values are set as admin:
- | courselistshortnames | 1 |
- When I enter the app
- And I log in as "student2"
- Then I should see "Course 1"
- And I should see "Course 2"
- And I should see "C1"
- And I should see "C2"
-
- Scenario: Student uses course list to enter course, then leaves it again
- When I enter the app
- And I log in as "student2"
- And I press "Course 2" near "Course overview" in the app
- Then the header should be "Course 2" in the app
- And I press the back button in the app
- Then the header should be "Acceptance test site" in the app
-
- Scenario: Student uses filter feature to reduce course list
- Given the following config values are set as admin:
- | courselistshortnames | 1 |
- And the following "courses" exist:
- | fullname | shortname |
- | Frog 3 | C3 |
- | Frog 4 | C4 |
- | Course 5 | C5 |
- | Toad 6 | C6 |
- And the following "course enrolments" exist:
- | user | course | role |
- | student2 | C3 | student |
- | student2 | C4 | student |
- | student2 | C5 | student |
- | student2 | C6 | student |
- # Create bogus courses so that the main ones aren't shown in the 'recently accessed' part.
- # Because these come later in alphabetical order, they may not be displayed in the lower part
- # which is OK.
- And the following "courses" exist:
- | fullname | shortname |
- | Zogus 1 | Z1 |
- | Zogus 2 | Z2 |
- | Zogus 3 | Z3 |
- | Zogus 4 | Z4 |
- | Zogus 5 | Z5 |
- | Zogus 6 | Z6 |
- | Zogus 7 | Z7 |
- | Zogus 8 | Z8 |
- | Zogus 9 | Z9 |
- | Zogus 10 | Z10 |
- And the following "course enrolments" exist:
- | user | course | role |
- | student2 | Z1 | student |
- | student2 | Z2 | student |
- | student2 | Z3 | student |
- | student2 | Z4 | student |
- | student2 | Z5 | student |
- | student2 | Z6 | student |
- | student2 | Z7 | student |
- | student2 | Z8 | student |
- | student2 | Z9 | student |
- | student2 | Z10 | student |
- When I enter the app
- And I log in as "student2"
- Then I should see "C1"
- And I should see "C2"
- And I should see "C3"
- And I should see "C4"
- And I should see "C5"
- And I should see "C6"
- And I press "more" near "Course overview" in the app
- And I press "Filter my courses" in the app
- And I set the field "Filter my courses" to "fr" in the app
- Then I should not see "C1"
- And I should not see "C2"
- And I should see "C3"
- And I should see "C4"
- And I should not see "C5"
- And I should not see "C6"
- And I press "more" near "Course overview" in the app
- And I press "Filter my courses" in the app
- Then I should see "C1"
- And I should see "C2"
- And I should see "C3"
- And I should see "C4"
- And I should see "C5"
- And I should see "C6"
diff --git a/course/tests/behat/behat_course.php b/course/tests/behat/behat_course.php
index 35465843b41a2..16fa6e3e3ad39 100644
--- a/course/tests/behat/behat_course.php
+++ b/course/tests/behat/behat_course.php
@@ -1144,11 +1144,8 @@ public function i_click_on_in_the_activity($element, $selectortype, $activitynam
protected function get_activity_element($element, $selectortype, $activityname) {
$activitynode = $this->get_activity_node($activityname);
- // Transforming to Behat selector/locator.
- list($selector, $locator) = $this->transform_selector($selectortype, $element);
- $exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' . $selectortype . '" in "' . $activityname . '" ');
-
- return $this->find($selector, $locator, $exception, $activitynode);
+ $exception = new ElementNotFoundException($this->getSession(), "'{$element}' '{$selectortype}' in '${activityname}'");
+ return $this->find($selectortype, $element, $exception, $activitynode);
}
/**
diff --git a/course/tests/behat/course_creation.feature b/course/tests/behat/course_creation.feature
index 2596eb281de38..859afcc8e0773 100644
--- a/course/tests/behat/course_creation.feature
+++ b/course/tests/behat/course_creation.feature
@@ -68,3 +68,31 @@ Feature: Managers can create courses
| id_enddate_day | 24 |
| id_enddate_month | October |
| id_enddate_year | 2016 |
+
+ Scenario: Create a course as a custom course creator
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | kevin | Kevin | the | kevin@example.com |
+ And the following "roles" exist:
+ | shortname | name | archetype |
+ | creator | Creator | |
+ And the following "system role assigns" exist:
+ | user | role | contextlevel |
+ | kevin | creator | System |
+ And I log in as "admin"
+ And I set the following system permissions of "Creator" role:
+ | capability | permission |
+ | moodle/course:create | Allow |
+ | moodle/course:manageactivities | Allow |
+ | moodle/course:viewparticipants | Allow |
+ And I log out
+ And I log in as "kevin"
+ And I am on site homepage
+ When I press "Add a new course"
+ And I set the following fields to these values:
+ | Course full name | My first course |
+ | Course short name | myfirstcourse |
+ And I press "Save and display"
+ And I follow "Participants"
+ Then I should see "Kevin the"
+ And I should see "Teacher"
diff --git a/course/tests/courselib_test.php b/course/tests/courselib_test.php
index 26197f01b8e0c..5e70ddff4b80b 100644
--- a/course/tests/courselib_test.php
+++ b/course/tests/courselib_test.php
@@ -3193,7 +3193,6 @@ public function test_course_get_user_administration_options_for_managers() {
$this->assertFalse($adminoptions->outcomes);
$this->assertTrue($adminoptions->badges);
$this->assertTrue($adminoptions->import);
- $this->assertFalse($adminoptions->publish);
$this->assertTrue($adminoptions->reset);
$this->assertTrue($adminoptions->roles);
}
@@ -3225,7 +3224,6 @@ public function test_course_get_user_administration_options_for_students() {
$this->assertFalse($adminoptions->outcomes);
$this->assertTrue($adminoptions->badges);
$this->assertFalse($adminoptions->import);
- $this->assertFalse($adminoptions->publish);
$this->assertFalse($adminoptions->reset);
$this->assertFalse($adminoptions->roles);
@@ -5021,6 +5019,7 @@ public function test_core_course_core_calendar_get_valid_event_timestart_range_w
* Test the course_get_recent_courses function.
*/
public function test_course_get_recent_courses() {
+ global $DB;
$this->resetAfterTest();
$generator = $this->getDataGenerator();
@@ -5043,9 +5042,15 @@ public function test_course_get_recent_courses() {
// No course accessed.
$this->assertCount(0, $result);
+ $time = time();
foreach ($courses as $course) {
$context = context_course::instance($course->id);
course_view($context);
+ $DB->set_field('user_lastaccess', 'timeaccess', $time, [
+ 'userid' => $student->id,
+ 'courseid' => $course->id,
+ ]);
+ $time++;
}
// Every course accessed.
@@ -5056,10 +5061,10 @@ public function test_course_get_recent_courses() {
$result = course_get_recent_courses($student->id, 2);
$this->assertCount(2, $result);
- // Every course accessed, with limit and offset. Should return only the last created course ($course[2]).
+ // Every course accessed, with limit and offset should return the first course.
$result = course_get_recent_courses($student->id, 3, 2);
$this->assertCount(1, $result);
- $this->assertArrayHasKey($courses[2]->id, $result);
+ $this->assertArrayHasKey($courses[0]->id, $result);
// Every course accessed, order by shortname DESC. The last create course ($course[2]) should have the greater shortname.
$result = course_get_recent_courses($student->id, 0, 0, 'shortname DESC');
@@ -5085,4 +5090,50 @@ public function test_course_get_recent_courses() {
$this->assertCount(3, $result);
$this->assertArrayNotHasKey($courses[0]->id, $result);
}
+
+ /**
+ * Data provider for test_course_modules_pending_deletion.
+ *
+ * @return array An array of arrays contain test data
+ */
+ public function provider_course_modules_pending_deletion() {
+ return [
+ 'Non-gradable activity, check all' => [['forum'], 0, false, true],
+ 'Gradable activity, check all' => [['assign'], 0, false, true],
+ 'Non-gradable activity, check gradables' => [['forum'], 0, true, false],
+ 'Gradable activity, check gradables' => [['assign'], 0, true, true],
+ 'Non-gradable within multiple, check all' => [['quiz', 'forum', 'assign'], 1, false, true],
+ 'Non-gradable within multiple, check gradables' => [['quiz', 'forum', 'assign'], 1, true, false],
+ 'Gradable within multiple, check all' => [['quiz', 'forum', 'assign'], 2, false, true],
+ 'Gradable within multiple, check gradables' => [['quiz', 'forum', 'assign'], 2, true, true],
+ ];
+ }
+
+ /**
+ * Tests the function course_modules_pending_deletion.
+ *
+ * @param string[] $modules A complete list aff all available modules before deletion
+ * @param int $indextodelete The index of the module in the $modules array that we want to test with
+ * @param bool $gradable The value to pass to the gradable argument of the course_modules_pending_deletion function
+ * @param bool $expected The expected result
+ * @dataProvider provider_course_modules_pending_deletion
+ */
+ public function test_course_modules_pending_deletion(array $modules, int $indextodelete, bool $gradable, bool $expected) {
+ $this->resetAfterTest();
+
+ // Ensure recyclebin is enabled.
+ set_config('coursebinenable', true, 'tool_recyclebin');
+
+ // Create course and modules.
+ $generator = $this->getDataGenerator();
+ $course = $generator->create_course();
+
+ $moduleinstances = [];
+ foreach ($modules as $module) {
+ $moduleinstances[] = $generator->create_module($module, array('course' => $course->id));
+ }
+
+ course_delete_module($moduleinstances[$indextodelete]->cmid, true); // Try to delete the instance asynchronously.
+ $this->assertEquals($expected, course_modules_pending_deletion($course->id, $gradable));
+ }
}
diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php
index ac06afab57c99..bc6560d4d8ded 100644
--- a/course/tests/externallib_test.php
+++ b/course/tests/externallib_test.php
@@ -958,7 +958,6 @@ public function test_get_course_contents() {
foreach ($sections[2]['modules'] as $module) {
if ($module['id'] == $urlcm->id and $module['modname'] == 'url') {
$this->assertContains('width=100,height=100', $module['onclick']);
- $this->assertContains('moodle.org', $module['customdata']);
$testexecuted = $testexecuted + 1;
}
}
@@ -2334,12 +2333,11 @@ public function test_get_user_administration_options() {
$this->assertFalse($adminoptions->outcomes);
$this->assertFalse($adminoptions->badges);
$this->assertFalse($adminoptions->import);
- $this->assertFalse($adminoptions->publish);
$this->assertFalse($adminoptions->reset);
$this->assertFalse($adminoptions->roles);
$this->assertFalse($adminoptions->editcompletion);
} else {
- $this->assertCount(15, $course['options']);
+ $this->assertCount(14, $course['options']);
$this->assertFalse($adminoptions->update);
$this->assertFalse($adminoptions->filters);
$this->assertFalse($adminoptions->reports);
@@ -2351,7 +2349,6 @@ public function test_get_user_administration_options() {
$this->assertFalse($adminoptions->outcomes);
$this->assertTrue($adminoptions->badges);
$this->assertFalse($adminoptions->import);
- $this->assertFalse($adminoptions->publish);
$this->assertFalse($adminoptions->reset);
$this->assertFalse($adminoptions->roles);
$this->assertFalse($adminoptions->editcompletion);
diff --git a/course/tests/indicators_test.php b/course/tests/indicators_test.php
index 1749a13a57645..3ad47f95e891e 100644
--- a/course/tests/indicators_test.php
+++ b/course/tests/indicators_test.php
@@ -28,6 +28,7 @@
global $CFG;
require_once(__DIR__ . '/../../lib/completionlib.php');
require_once(__DIR__ . '/../../completion/criteria/completion_criteria_self.php');
+require_once(__DIR__ . '/../../analytics/tests/fixtures/test_target_course_users.php');
/**
* Unit tests for core_course indicators.
@@ -313,4 +314,30 @@ public function test_potential_social() {
// Page social is level 1 (the lower level).
$this->assertEquals($indicator::get_min_value(), $values[$cm2->id][0]);
}
+
+ /**
+ * test_activities_due
+ *
+ * @return void
+ */
+ public function test_activities_due() {
+ global $DB;
+
+ $this->resetAfterTest(true);
+ $this->setAdminuser();
+
+ $course1 = $this->getDataGenerator()->create_course();
+ $user1 = $this->getDataGenerator()->create_user();
+ $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student');
+
+ $target = \core_analytics\manager::get_target('test_target_course_users');
+ $indicators = array('\core_course\analytics\indicator\activities_due');
+ foreach ($indicators as $key => $indicator) {
+ $indicators[$key] = \core_analytics\manager::get_indicator($indicator);
+ }
+
+ $model = \core_analytics\model::create($target, $indicators);
+ $model->enable('\core\analytics\time_splitting\single_range');
+ $model->train();
+ }
}
diff --git a/course/tests/restore_test.php b/course/tests/restore_test.php
index 470e03b13daa0..4f659902ffb50 100644
--- a/course/tests/restore_test.php
+++ b/course/tests/restore_test.php
@@ -131,6 +131,157 @@ protected function restore_to_new_course($backupid, $userid = 2) {
return $this->restore_course($backupid, 0, $userid);
}
+ /**
+ * Restore a course.
+ *
+ * @param int $backupid The backup ID.
+ * @param int $courseid The course ID to restore in, or 0.
+ * @param int $userid The ID of the user performing the restore.
+ * @param int $target THe target of the restore.
+ *
+ * @return stdClass The updated course object.
+ */
+ protected function async_restore_course($backupid, $courseid, $userid, $target) {
+ global $DB;
+
+ if (!$courseid) {
+ $target = backup::TARGET_NEW_COURSE;
+ $categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
+ $courseid = restore_dbops::create_new_course('Tmp', 'tmp', $categoryid);
+ }
+
+ $rc = new restore_controller($backupid, $courseid, backup::INTERACTIVE_NO, backup::MODE_ASYNC, $userid, $target);
+ $target == backup::TARGET_NEW_COURSE ?: $rc->get_plan()->get_setting('overwrite_conf')->set_value(true);
+ $this->assertTrue($rc->execute_precheck());
+
+ $restoreid = $rc->get_restoreid();
+ $rc->destroy();
+
+ // Create the adhoc task.
+ $asynctask = new \core\task\asynchronous_restore_task();
+ $asynctask->set_blocking(false);
+ $asynctask->set_custom_data(array('backupid' => $restoreid));
+ \core\task\manager::queue_adhoc_task($asynctask);
+
+ // We are expecting trace output during this test.
+ $this->expectOutputRegex("/$restoreid/");
+
+ // Execute adhoc task.
+ $now = time();
+ $task = \core\task\manager::get_next_adhoc_task($now);
+ $this->assertInstanceOf('\\core\\task\\asynchronous_restore_task', $task);
+ $task->execute();
+ \core\task\manager::adhoc_task_complete($task);
+
+ $course = $DB->get_record('course', array('id' => $rc->get_courseid()));
+
+ return $course;
+ }
+
+ /**
+ * Restore a course to an existing course.
+ *
+ * @param int $backupid The backup ID.
+ * @param int $courseid The course ID to restore in.
+ * @param int $userid The ID of the user performing the restore.
+ * @param int $target The type of restore we are performing.
+ * @return stdClass The updated course object.
+ */
+ protected function async_restore_to_existing_course($backupid, $courseid,
+ $userid = 2, $target = backup::TARGET_CURRENT_ADDING) {
+ return $this->async_restore_course($backupid, $courseid, $userid, $target);
+ }
+
+ /**
+ * Restore a course to a new course.
+ *
+ * @param int $backupid The backup ID.
+ * @param int $userid The ID of the user performing the restore.
+ * @return stdClass The new course object.
+ */
+ protected function async_restore_to_new_course($backupid, $userid = 2) {
+ return $this->async_restore_course($backupid, 0, $userid, 0);
+ }
+
+ public function test_async_restore_existing_idnumber_in_new_course() {
+ $this->resetAfterTest();
+
+ $dg = $this->getDataGenerator();
+ $c1 = $dg->create_course(['idnumber' => 'ABC']);
+ $backupid = $this->backup_course($c1->id);
+ $c2 = $this->async_restore_to_new_course($backupid);
+
+ // The ID number is set empty.
+ $this->assertEquals('', $c2->idnumber);
+ }
+
+ public function test_async_restore_course_info_in_existing_course() {
+ global $DB;
+ $this->resetAfterTest();
+ $dg = $this->getDataGenerator();
+
+ $this->assertEquals(1, get_config('restore', 'restore_merge_course_shortname'));
+ $this->assertEquals(1, get_config('restore', 'restore_merge_course_fullname'));
+ $this->assertEquals(1, get_config('restore', 'restore_merge_course_startdate'));
+
+ $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
+
+ // Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
+ $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
+ 'startdate' => $startdate]);
+ $chat1 = $dg->create_module('chat', ['name' => 'First', 'course' => $c1->id, 'chattime' => $c1->startdate + 1 * WEEKSECS]);
+ $c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
+ 'startdate' => $startdate + 2 * WEEKSECS]);
+ $chat2 = $dg->create_module('chat', ['name' => 'Second', 'course' => $c2->id, 'chattime' => $c2->startdate + 1 * WEEKSECS]);
+ $backupid = $this->backup_course($c1->id);
+
+ // The information is restored but adapted because names are already taken.
+ $c2 = $this->async_restore_to_existing_course($backupid, $c2->id);
+ $this->assertEquals('SN_1', $c2->shortname);
+ $this->assertEquals('FN copy 1', $c2->fullname);
+ $this->assertEquals('DESC', $c2->summary);
+ $this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
+ $this->assertEquals($startdate, $c2->startdate);
+
+ // Now course c2 has two chats - one ('Second') was already there and one ('First') was restored from the backup.
+ // Their dates are exactly the same as they were in the original modules.
+ $restoredchat1 = $DB->get_record('chat', ['name' => 'First', 'course' => $c2->id]);
+ $restoredchat2 = $DB->get_record('chat', ['name' => 'Second', 'course' => $c2->id]);
+ $this->assertEquals($chat1->chattime, $restoredchat1->chattime);
+ $this->assertEquals($chat2->chattime, $restoredchat2->chattime);
+ }
+
+ public function test_async_restore_course_info_in_existing_course_delete_first() {
+ global $DB;
+ $this->resetAfterTest();
+ $dg = $this->getDataGenerator();
+
+ $this->assertEquals(1, get_config('restore', 'restore_merge_course_shortname'));
+ $this->assertEquals(1, get_config('restore', 'restore_merge_course_fullname'));
+ $this->assertEquals(1, get_config('restore', 'restore_merge_course_startdate'));
+
+ $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
+
+ // Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
+ $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
+ 'startdate' => $startdate]);
+ $chat1 = $dg->create_module('chat', ['name' => 'First', 'course' => $c1->id, 'chattime' => $c1->startdate + 1 * WEEKSECS]);
+ $c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
+ 'startdate' => $startdate + 2 * WEEKSECS]);
+ $chat2 = $dg->create_module('chat', ['name' => 'Second', 'course' => $c2->id, 'chattime' => $c2->startdate + 1 * WEEKSECS]);
+ $backupid = $this->backup_course($c1->id);
+
+ // The information is restored and the existing course settings is modified.
+ $c2 = $this->async_restore_to_existing_course($backupid, $c2->id, 2, backup::TARGET_CURRENT_DELETING);
+ $this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
+
+ // Now course2 should have a new forum with the original forum deleted.
+ $restoredchat1 = $DB->get_record('chat', ['name' => 'First', 'course' => $c2->id]);
+ $restoredchat2 = $DB->get_record('chat', ['name' => 'Second', 'course' => $c2->id]);
+ $this->assertEquals($chat1->chattime, $restoredchat1->chattime);
+ $this->assertEmpty($restoredchat2);
+ }
+
public function test_restore_existing_idnumber_in_new_course() {
$this->resetAfterTest();
diff --git a/customfield/field/checkbox/classes/data_controller.php b/customfield/field/checkbox/classes/data_controller.php
index 881e515ad4c21..4d080d7c449c9 100644
--- a/customfield/field/checkbox/classes/data_controller.php
+++ b/customfield/field/checkbox/classes/data_controller.php
@@ -55,8 +55,8 @@ public function instance_form_definition(\MoodleQuickForm $mform) {
$field = $this->get_field();
$config = $field->get('configdata');
$elementname = $this->get_form_element_name();
- // TODO MDL-65506 element 'advcheckbox' does not support 'required' rule. If checkbox is required (i.e. "agree to terms")
- // then use 'checkbox' form element.
+ // If checkbox is required (i.e. "agree to terms") then use 'checkbox' form element.
+ // The advcheckbox element cannot be used for required fields because advcheckbox elements always provide a value.
$isrequired = $field->get_configdata_property('required');
$mform->addElement($isrequired ? 'checkbox' : 'advcheckbox', $elementname, $this->get_field()->get_formatted_name());
$mform->setDefault($elementname, $config['checkbydefault']);
diff --git a/customfield/field/text/lang/en/customfield_text.php b/customfield/field/text/lang/en/customfield_text.php
index de273bf7bb30c..e878d29215caa 100644
--- a/customfield/field/text/lang/en/customfield_text.php
+++ b/customfield/field/text/lang/en/customfield_text.php
@@ -31,7 +31,7 @@
$string['errorconfigmaxlen'] = 'The maximum number of characters allowed must be between 1 and 1333.';
$string['errormaxlength'] = 'The maximum number of characters allowed in this field is {$a}.';
$string['islink'] = 'Link field';
-$string['islink_help'] = 'To transform the text into a link, enter a URL containing $$ as a placeholder, where $$ will be replaced with the text. For example, to transform a Twitter ID to a link, enter http://twitter.com/$$.';
+$string['islink_help'] = 'To transform the text into a link, enter a URL containing $$ as a placeholder, where $$ will be replaced with the text. For example, to transform a Twitter ID to a link, enter https://twitter.com/$$.';
$string['ispassword'] = 'Password field';
$string['linktarget'] = 'Link target';
$string['maxlength'] = 'Maximum number of characters';
diff --git a/customfield/tests/api_test.php b/customfield/tests/api_test.php
index 45d50d1712e72..e76d410e05b91 100644
--- a/customfield/tests/api_test.php
+++ b/customfield/tests/api_test.php
@@ -38,17 +38,11 @@
class core_customfield_api_testcase extends advanced_testcase {
/**
- * Tests set up.
- */
- public function setUp() {
- $this->resetAfterTest();
- }
-
- /**
- * Get generator
+ * Get generator.
+ *
* @return core_customfield_generator
*/
- protected function get_generator() : core_customfield_generator {
+ protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
@@ -57,7 +51,7 @@ protected function get_generator() : core_customfield_generator {
*
* @param array $expected
* @param array $array array of objects with "get($property)" method
- * @param sring $propertyname
+ * @param string $propertyname
*/
protected function assert_property_in_array($expected, $array, $propertyname) {
$this->assertEquals($expected, array_values(array_map(function($a) use ($propertyname) {
@@ -72,6 +66,8 @@ protected function assert_property_in_array($expected, $array, $propertyname) {
* in the interface using drag-drop.
*/
public function test_move_category() {
+ $this->resetAfterTest();
+
// Create the categories.
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0];
$id0 = $this->get_generator()->create_category($params)->get('id');
@@ -121,6 +117,8 @@ public function test_move_category() {
* Tests for \core_customfield\api::get_categories_with_fields() behaviour.
*/
public function test_get_categories_with_fields() {
+ $this->resetAfterTest();
+
// Create the categories.
$options = [
'component' => 'core_course',
@@ -155,6 +153,8 @@ public function test_get_categories_with_fields() {
* Test for functions api::save_category() and rename_category)
*/
public function test_save_category() {
+ $this->resetAfterTest();
+
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0, 'name' => 'Cat1',
'contextid' => context_system::instance()->id];
$c1 = category_controller::create(0, (object)$params);
@@ -188,6 +188,8 @@ public function test_save_category() {
* Test for function handler::create_category
*/
public function test_create_category() {
+ $this->resetAfterTest();
+
$handler = \core_course\customfield\course_handler::create();
$c1id = $handler->create_category();
$c1 = $handler->get_categories_with_fields()[$c1id];
@@ -210,6 +212,8 @@ public function test_create_category() {
* Tests for \core_customfield\api::delete_category() behaviour.
*/
public function test_delete_category_with_fields() {
+ $this->resetAfterTest();
+
global $DB;
// Create two categories with fields and data.
$options = [
diff --git a/customfield/tests/category_controller_test.php b/customfield/tests/category_controller_test.php
index 656bc5bc79da4..04ce151e65e68 100644
--- a/customfield/tests/category_controller_test.php
+++ b/customfield/tests/category_controller_test.php
@@ -37,21 +37,20 @@
class core_customfield_category_controller_testcase extends advanced_testcase {
/**
- * Tests set up.
- */
- public function setUp() {
- $this->resetAfterTest();
- }
-
- /**
- * Get generator
+ * Get generator.
+ *
* @return core_customfield_generator
*/
- protected function get_generator() : core_customfield_generator {
+ protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
+ /**
+ * Test for the field_controller::__construct function.
+ */
public function test_constructor() {
+ $this->resetAfterTest();
+
$c = category_controller::create(0, (object)['component' => 'core_course', 'area' => 'course', 'itemid' => 0]);
$handler = $c->get_handler();
$this->assertTrue($c instanceof category_controller);
@@ -75,6 +74,8 @@ public function test_constructor() {
*/
public function test_constructor_errors() {
global $DB;
+ $this->resetAfterTest();
+
$cat = $this->get_generator()->create_category();
$catrecord = $cat->to_record();
@@ -173,6 +174,7 @@ public function test_constructor_errors() {
* \core_customfield\category_controller::get()
*/
public function test_create_category() {
+ $this->resetAfterTest();
// Create the category.
$lpg = $this->get_generator();
@@ -201,6 +203,8 @@ public function test_create_category() {
* Tests for \core_customfield\category_controller::set() behaviour.
*/
public function test_rename_category() {
+ $this->resetAfterTest();
+
// Create the category.
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0, 'name' => 'Cat1',
'contextid' => context_system::instance()->id];
@@ -224,6 +228,8 @@ public function test_rename_category() {
* Tests for \core_customfield\category_controller::delete() behaviour.
*/
public function test_delete_category() {
+ $this->resetAfterTest();
+
// Create the category.
$lpg = $this->get_generator();
$category0 = $lpg->create_category();
diff --git a/customfield/tests/data_controller_test.php b/customfield/tests/data_controller_test.php
index ac5b4056a07b8..d125c5c9c2168 100644
--- a/customfield/tests/data_controller_test.php
+++ b/customfield/tests/data_controller_test.php
@@ -35,17 +35,11 @@
class core_customfield_data_controller_testcase extends advanced_testcase {
/**
- * Tests set up.
- */
- public function setUp() {
- $this->resetAfterTest();
- }
-
- /**
- * Get generator
+ * Get generator.
+ *
* @return core_customfield_generator
*/
- protected function get_generator() : core_customfield_generator {
+ protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
@@ -54,6 +48,8 @@ protected function get_generator() : core_customfield_generator {
*/
public function test_constructor() {
global $DB;
+ $this->resetAfterTest();
+
// Create a course, fields category and fields.
$course = $this->getDataGenerator()->create_course();
$category0 = $this->get_generator()->create_category(['name' => 'aaaa']);
@@ -122,6 +118,8 @@ public function test_constructor() {
*/
public function test_constructor_errors() {
global $DB;
+ $this->resetAfterTest();
+
// Create a category, field and data.
$category = $this->get_generator()->create_category();
$field = $this->get_generator()->create_field(['categoryid' => $category->get('id')]);
@@ -180,4 +178,4 @@ public function test_constructor_errors() {
$this->assertEquals(moodle_exception::class, get_class($e));
}
}
-}
\ No newline at end of file
+}
diff --git a/customfield/tests/field_controller_test.php b/customfield/tests/field_controller_test.php
index b7044695be918..a642919e2624a 100644
--- a/customfield/tests/field_controller_test.php
+++ b/customfield/tests/field_controller_test.php
@@ -39,17 +39,11 @@
class core_customfield_field_controller_testcase extends advanced_testcase {
/**
- * Tests set up.
- */
- public function setUp() {
- $this->resetAfterTest();
- }
-
- /**
- * Get generator
+ * Get generator.
+ *
* @return core_customfield_generator
*/
- protected function get_generator() : core_customfield_generator {
+ protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
@@ -58,6 +52,8 @@ protected function get_generator() : core_customfield_generator {
*/
public function test_constructor() {
global $DB;
+ $this->resetAfterTest();
+
// Create the category.
$category0 = $this->get_generator()->create_category();
@@ -103,6 +99,8 @@ public function test_constructor() {
*/
public function test_constructor_errors() {
global $DB;
+ $this->resetAfterTest();
+
// Create a category and a field.
$category = $this->get_generator()->create_category();
$field = $this->get_generator()->create_field(['categoryid' => $category->get('id')]);
@@ -175,6 +173,8 @@ public function test_constructor_errors() {
*/
public function test_create_field() {
global $DB;
+ $this->resetAfterTest();
+
$lpg = $this->get_generator();
$category = $lpg->create_category();
$fields = $DB->get_records(\core_customfield\field::TABLE, ['categoryid' => $category->get('id')]);
@@ -203,6 +203,8 @@ public function test_create_field() {
*/
public function test_delete_field() {
global $DB;
+ $this->resetAfterTest();
+
$lpg = $this->get_generator();
$category = $lpg->create_category();
$fields = $DB->get_records(\core_customfield\field::TABLE, ['categoryid' => $category->get('id')]);
@@ -229,6 +231,8 @@ public function test_delete_field() {
* Tests for \core_customfield\field_controller::get_configdata_property() behaviour.
*/
public function test_get_configdata_property() {
+ $this->resetAfterTest();
+
$lpg = $this->get_generator();
$category = $lpg->create_category();
$configdata = ['a' => 'b', 'c' => ['d', 'e']];
@@ -243,4 +247,4 @@ public function test_get_configdata_property() {
$this->assertEquals(['d', 'e'], $field->get_configdata_property('c'));
$this->assertEquals(null, $field->get_configdata_property('x'));
}
-}
\ No newline at end of file
+}
diff --git a/customfield/tests/generator_test.php b/customfield/tests/generator_test.php
index 4788d9cf3470b..c5335c37d9fef 100644
--- a/customfield/tests/generator_test.php
+++ b/customfield/tests/generator_test.php
@@ -39,7 +39,7 @@ class core_customfield_generator_testcase extends advanced_testcase {
* Get generator
* @return core_customfield_generator
*/
- protected function get_generator() : core_customfield_generator {
+ protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
diff --git a/customfield/tests/privacy_test.php b/customfield/tests/privacy_test.php
index 9a15ced565881..4a63085fb3f20 100644
--- a/customfield/tests/privacy_test.php
+++ b/customfield/tests/privacy_test.php
@@ -38,63 +38,59 @@
*/
class core_customfield_privacy_testcase extends provider_testcase {
- /** @var stdClass[] */
- private $courses = [];
- /** @var \core_customfield\category_controller[] */
- private $cfcats = [];
- /** @var \core_customfield\field_controller[] */
- private $cffields = [];
-
/**
- * Set up
+ * Generate data.
+ *
+ * @return array
*/
- public function setUp() {
+ protected function generate_test_data(): array {
$this->resetAfterTest();
- $this->cfcats[1] = $this->get_generator()->create_category();
- $this->cfcats[2] = $this->get_generator()->create_category();
- $this->cffields[11] = $this->get_generator()->create_field(
- ['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'checkbox']);
- $this->cffields[12] = $this->get_generator()->create_field(
- ['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'date']);
- $this->cffields[13] = $this->get_generator()->create_field(
- ['categoryid' => $this->cfcats[1]->get('id'),
+ $generator = $this->getDataGenerator()->get_plugin_generator('core_customfield');
+ $cfcats[1] = $generator->create_category();
+ $cfcats[2] = $generator->create_category();
+ $cffields[11] = $generator->create_field(
+ ['categoryid' => $cfcats[1]->get('id'), 'type' => 'checkbox']);
+ $cffields[12] = $generator->create_field(
+ ['categoryid' => $cfcats[1]->get('id'), 'type' => 'date']);
+ $cffields[13] = $generator->create_field(
+ ['categoryid' => $cfcats[1]->get('id'),
'type' => 'select', 'configdata' => ['options' => "a\nb\nc"]]);
- $this->cffields[14] = $this->get_generator()->create_field(
- ['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'text']);
- $this->cffields[15] = $this->get_generator()->create_field(
- ['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'textarea']);
- $this->cffields[21] = $this->get_generator()->create_field(
- ['categoryid' => $this->cfcats[2]->get('id')]);
- $this->cffields[22] = $this->get_generator()->create_field(
- ['categoryid' => $this->cfcats[2]->get('id')]);
-
- $this->courses[1] = $this->getDataGenerator()->create_course();
- $this->courses[2] = $this->getDataGenerator()->create_course();
- $this->courses[3] = $this->getDataGenerator()->create_course();
-
- $this->get_generator()->add_instance_data($this->cffields[11], $this->courses[1]->id, 1);
- $this->get_generator()->add_instance_data($this->cffields[12], $this->courses[1]->id, 1546300800);
- $this->get_generator()->add_instance_data($this->cffields[13], $this->courses[1]->id, 2);
- $this->get_generator()->add_instance_data($this->cffields[14], $this->courses[1]->id, 'Hello1');
- $this->get_generator()->add_instance_data($this->cffields[15], $this->courses[1]->id,
+ $cffields[14] = $generator->create_field(
+ ['categoryid' => $cfcats[1]->get('id'), 'type' => 'text']);
+ $cffields[15] = $generator->create_field(
+ ['categoryid' => $cfcats[1]->get('id'), 'type' => 'textarea']);
+ $cffields[21] = $generator->create_field(
+ ['categoryid' => $cfcats[2]->get('id')]);
+ $cffields[22] = $generator->create_field(
+ ['categoryid' => $cfcats[2]->get('id')]);
+
+ $courses[1] = $this->getDataGenerator()->create_course();
+ $courses[2] = $this->getDataGenerator()->create_course();
+ $courses[3] = $this->getDataGenerator()->create_course();
+
+ $generator->add_instance_data($cffields[11], $courses[1]->id, 1);
+ $generator->add_instance_data($cffields[12], $courses[1]->id, 1546300800);
+ $generator->add_instance_data($cffields[13], $courses[1]->id, 2);
+ $generator->add_instance_data($cffields[14], $courses[1]->id, 'Hello1');
+ $generator->add_instance_data($cffields[15], $courses[1]->id,
['text' => '
Hi there
', 'format' => FORMAT_HTML]);
- $this->get_generator()->add_instance_data($this->cffields[21], $this->courses[1]->id, 'hihi1');
+ $generator->add_instance_data($cffields[21], $courses[1]->id, 'hihi1');
- $this->get_generator()->add_instance_data($this->cffields[14], $this->courses[2]->id, 'Hello2');
+ $generator->add_instance_data($cffields[14], $courses[2]->id, 'Hello2');
- $this->get_generator()->add_instance_data($this->cffields[21], $this->courses[2]->id, 'hihi2');
+ $generator->add_instance_data($cffields[21], $courses[2]->id, 'hihi2');
- $this->setUser($this->getDataGenerator()->create_user());
- }
+ $user = $this->getDataGenerator()->create_user();
+ $this->setUser($user);
- /**
- * Get generator
- * @return core_customfield_generator
- */
- protected function get_generator() : core_customfield_generator {
- return $this->getDataGenerator()->get_plugin_generator('core_customfield');
+ return [
+ 'user' => $user,
+ 'cfcats' => $cfcats,
+ 'cffields' => $cffields,
+ 'courses' => $courses,
+ ];
}
/**
@@ -111,11 +107,17 @@ public function test_get_metadata() {
*/
public function test_get_customfields_data_contexts() {
global $DB;
- list($sql, $params) = $DB->get_in_or_equal([$this->courses[1]->id, $this->courses[2]->id], SQL_PARAMS_NAMED);
+ [
+ 'cffields' => $cffields,
+ 'cfcats' => $cfcats,
+ 'courses' => $courses,
+ ] = $this->generate_test_data();
+
+ list($sql, $params) = $DB->get_in_or_equal([$courses[1]->id, $courses[2]->id], SQL_PARAMS_NAMED);
$r = provider::get_customfields_data_contexts('core_course', 'course', '=0',
$sql, $params);
- $this->assertEquals([context_course::instance($this->courses[1]->id)->id,
- context_course::instance($this->courses[2]->id)->id],
+ $this->assertEquals([context_course::instance($courses[1]->id)->id,
+ context_course::instance($courses[2]->id)->id],
$r->get_contextids(), '', 0, 10, true);
}
@@ -123,6 +125,8 @@ public function test_get_customfields_data_contexts() {
* Test for provider::get_customfields_configuration_contexts()
*/
public function test_get_customfields_configuration_contexts() {
+ $this->generate_test_data();
+
$r = provider::get_customfields_configuration_contexts('core_course', 'course');
$this->assertEquals([context_system::instance()->id], $r->get_contextids());
}
@@ -132,13 +136,20 @@ public function test_get_customfields_configuration_contexts() {
*/
public function test_export_customfields_data() {
global $USER, $DB;
+ $this->resetAfterTest();
+ [
+ 'cffields' => $cffields,
+ 'cfcats' => $cfcats,
+ 'courses' => $courses,
+ ] = $this->generate_test_data();
+
// Hack one of the fields so it has an invalid field type.
- $invalidfieldid = $this->cffields[21]->get('id');
+ $invalidfieldid = $cffields[21]->get('id');
$DB->update_record('customfield_field', ['id' => $invalidfieldid, 'type' => 'invalid']);
- $context = context_course::instance($this->courses[1]->id);
+ $context = context_course::instance($courses[1]->id);
$contextlist = new approved_contextlist($USER, 'core_customfield', [$context->id]);
- provider::export_customfields_data($contextlist, 'core_course', 'course', '=0', '=:i', ['i' => $this->courses[1]->id]);
+ provider::export_customfields_data($contextlist, 'core_course', 'course', '=0', '=:i', ['i' => $courses[1]->id]);
/** @var core_privacy\tests\request\content_writer $writer */
$writer = writer::with_context($context);
@@ -147,7 +158,7 @@ public function test_export_customfields_data() {
$invaldfieldischecked = false;
foreach ($DB->get_records('customfield_data', []) as $dbrecord) {
$data = $writer->get_data(['Custom fields data', $dbrecord->id]);
- if ($dbrecord->instanceid == $this->courses[1]->id) {
+ if ($dbrecord->instanceid == $courses[1]->id) {
$this->assertEquals($dbrecord->fieldid, $data->fieldid);
$this->assertNotEmpty($data->fieldtype);
$this->assertNotEmpty($data->fieldshortname);
@@ -167,10 +178,17 @@ public function test_export_customfields_data() {
*/
public function test_delete_customfields_data() {
global $USER, $DB;
- $approvedcontexts = new approved_contextlist($USER, 'core_course', [context_course::instance($this->courses[1]->id)->id]);
+ $this->resetAfterTest();
+ [
+ 'cffields' => $cffields,
+ 'cfcats' => $cfcats,
+ 'courses' => $courses,
+ ] = $this->generate_test_data();
+
+ $approvedcontexts = new approved_contextlist($USER, 'core_course', [context_course::instance($courses[1]->id)->id]);
provider::delete_customfields_data($approvedcontexts, 'core_course', 'course');
- $this->assertEmpty($DB->get_records('customfield_data', ['instanceid' => $this->courses[1]->id]));
- $this->assertNotEmpty($DB->get_records('customfield_data', ['instanceid' => $this->courses[2]->id]));
+ $this->assertEmpty($DB->get_records('customfield_data', ['instanceid' => $courses[1]->id]));
+ $this->assertNotEmpty($DB->get_records('customfield_data', ['instanceid' => $courses[2]->id]));
}
/**
@@ -178,9 +196,16 @@ public function test_delete_customfields_data() {
*/
public function test_delete_customfields_configuration() {
global $USER, $DB;
+ $this->resetAfterTest();
+ [
+ 'cffields' => $cffields,
+ 'cfcats' => $cfcats,
+ 'courses' => $courses,
+ ] = $this->generate_test_data();
+
// Remember the list of fields in the category 2 before we delete it.
- $catid1 = $this->cfcats[1]->get('id');
- $catid2 = $this->cfcats[2]->get('id');
+ $catid1 = $cfcats[1]->get('id');
+ $catid2 = $cfcats[2]->get('id');
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid2]);
$this->assertNotEmpty($fids2);
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
@@ -208,9 +233,16 @@ public function test_delete_customfields_configuration() {
*/
public function test_delete_customfields_configuration_for_context() {
global $USER, $DB;
+ $this->resetAfterTest();
+ [
+ 'cffields' => $cffields,
+ 'cfcats' => $cfcats,
+ 'courses' => $courses,
+ ] = $this->generate_test_data();
+
// Remember the list of fields in the category 2 before we delete it.
- $catid1 = $this->cfcats[1]->get('id');
- $catid2 = $this->cfcats[2]->get('id');
+ $catid1 = $cfcats[1]->get('id');
+ $catid2 = $cfcats[2]->get('id');
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid2]);
$this->assertNotEmpty($fids2);
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
@@ -238,12 +270,19 @@ public function test_delete_customfields_configuration_for_context() {
*/
public function test_delete_customfields_data_for_context() {
global $DB;
+ $this->resetAfterTest();
+ [
+ 'cffields' => $cffields,
+ 'cfcats' => $cfcats,
+ 'courses' => $courses,
+ ] = $this->generate_test_data();
+
provider::delete_customfields_data_for_context('core_course', 'course',
- context_course::instance($this->courses[1]->id));
+ context_course::instance($courses[1]->id));
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', '1=1', []);
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
- $fparams['course1'] = $this->courses[1]->id;
- $fparams['course2'] = $this->courses[2]->id;
+ $fparams['course1'] = $courses[1]->id;
+ $fparams['course2'] = $courses[2]->id;
$this->assertEmpty($DB->get_records_select('customfield_data', 'instanceid = :course1 AND fieldid ' . $fsql, $fparams));
$this->assertNotEmpty($DB->get_records_select('customfield_data', 'instanceid = :course2 AND fieldid ' . $fsql, $fparams));
}
diff --git a/dataformat/pdf/classes/writer.php b/dataformat/pdf/classes/writer.php
index 0559c93aebc0e..1f204d83e6174 100644
--- a/dataformat/pdf/classes/writer.php
+++ b/dataformat/pdf/classes/writer.php
@@ -89,6 +89,11 @@ public function start_sheet($columns) {
public function write_record($record, $rownum) {
$rowheight = 0;
+ // If $record is an object convert it to an array.
+ if (is_object($record)) {
+ $record = (array)$record;
+ }
+
foreach ($record as $cell) {
$rowheight = max($rowheight, $this->pdf->getStringHeight($this->colwidth, $cell, false, true, '', 1));
}
@@ -99,12 +104,19 @@ public function write_record($record, $rownum) {
$this->print_heading();
}
- $total = count($record);
- $counter = 1;
- foreach ($record as $cell) {
- $nextposition = ($counter == $total) ? 1 : 0;
+ // Get the last key for this record.
+ end($record);
+ $lastkey = key($record);
+
+ // Reset the record pointer.
+ reset($record);
+
+ // Loop through each element.
+ foreach ($record as $key => $cell) {
+ // Determine whether we're at the last element of the record.
+ $nextposition = ($lastkey === $key) ? 1 : 0;
+ // Write the element.
$this->pdf->Multicell($this->colwidth, $rowheight, $cell, 1, 'L', false, $nextposition);
- $counter++;
}
}
diff --git a/enrol/database/db/upgrade.php b/enrol/database/db/upgrade.php
index ca2733c53cb7c..9c288eb34e2b8 100644
--- a/enrol/database/db/upgrade.php
+++ b/enrol/database/db/upgrade.php
@@ -39,5 +39,8 @@ function xmldb_enrol_database_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/enrol/externallib.php b/enrol/externallib.php
index 593541e131a72..89cff4856fa0d 100644
--- a/enrol/externallib.php
+++ b/enrol/externallib.php
@@ -1020,6 +1020,70 @@ public static function edit_user_enrolment_returns() {
);
}
+ /**
+ * Returns description of submit_user_enrolment_form parameters.
+ *
+ * @return external_function_parameters.
+ */
+ public static function submit_user_enrolment_form_parameters() {
+ return new external_function_parameters([
+ 'formdata' => new external_value(PARAM_RAW, 'The data from the event form'),
+ ]);
+ }
+
+ /**
+ * External function that handles the user enrolment form submission.
+ *
+ * @param string $formdata The user enrolment form data in s URI encoded param string
+ * @return array An array consisting of the processing result and error flag, if available
+ */
+ public static function submit_user_enrolment_form($formdata) {
+ global $CFG, $DB, $PAGE;
+
+ // Parameter validation.
+ $params = self::validate_parameters(self::submit_user_enrolment_form_parameters(), ['formdata' => $formdata]);
+
+ $data = [];
+ parse_str($params['formdata'], $data);
+
+ $userenrolment = $DB->get_record('user_enrolments', ['id' => $data['ue']], '*', MUST_EXIST);
+ $instance = $DB->get_record('enrol', ['id' => $userenrolment->enrolid], '*', MUST_EXIST);
+ $plugin = enrol_get_plugin($instance->enrol);
+ $course = get_course($instance->courseid);
+ $context = context_course::instance($course->id);
+ self::validate_context($context);
+
+ require_once("$CFG->dirroot/enrol/editenrolment_form.php");
+ $customformdata = [
+ 'ue' => $userenrolment,
+ 'modal' => true,
+ 'enrolinstancename' => $plugin->get_instance_name($instance)
+ ];
+ $mform = new enrol_user_enrolment_form(null, $customformdata, 'post', '', null, true, $data);
+
+ if ($validateddata = $mform->get_data()) {
+ require_once($CFG->dirroot . '/enrol/locallib.php');
+ $manager = new course_enrolment_manager($PAGE, $course);
+ $result = $manager->edit_enrolment($userenrolment, $validateddata);
+
+ return ['result' => $result];
+ } else {
+ return ['result' => false, 'validationerror' => true];
+ }
+ }
+
+ /**
+ * Returns description of submit_user_enrolment_form() result value
+ *
+ * @return external_description
+ */
+ public static function submit_user_enrolment_form_returns() {
+ return new external_single_structure([
+ 'result' => new external_value(PARAM_BOOL, 'True if the user\'s enrolment was successfully updated'),
+ 'validationerror' => new external_value(PARAM_BOOL, 'Indicates invalid form data', VALUE_DEFAULT, false),
+ ]);
+ }
+
/**
* Returns description of unenrol_user_enrolment() parameters
*
diff --git a/enrol/flatfile/db/upgrade.php b/enrol/flatfile/db/upgrade.php
index c286910f29c8e..9e216f6fac30f 100644
--- a/enrol/flatfile/db/upgrade.php
+++ b/enrol/flatfile/db/upgrade.php
@@ -39,5 +39,8 @@ function xmldb_enrol_flatfile_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/enrol/guest/db/upgrade.php b/enrol/guest/db/upgrade.php
index a4f9d25eb980b..81fa08cb9bca1 100644
--- a/enrol/guest/db/upgrade.php
+++ b/enrol/guest/db/upgrade.php
@@ -39,5 +39,8 @@ function xmldb_enrol_guest_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/enrol/imsenterprise/db/upgrade.php b/enrol/imsenterprise/db/upgrade.php
index d89f2962cbad4..137602d74f4f5 100644
--- a/enrol/imsenterprise/db/upgrade.php
+++ b/enrol/imsenterprise/db/upgrade.php
@@ -45,5 +45,8 @@ function xmldb_enrol_imsenterprise_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/enrol/locallib.php b/enrol/locallib.php
index c77e1510c9fa6..dbe8636395d41 100644
--- a/enrol/locallib.php
+++ b/enrol/locallib.php
@@ -1191,7 +1191,7 @@ private function prepare_user_for_display($user, $extrafields, $now) {
);
foreach ($extrafields as $field) {
- $details[$field] = $user->{$field};
+ $details[$field] = s($user->{$field});
}
// Last time user has accessed the site.
diff --git a/enrol/lti/classes/helper.php b/enrol/lti/classes/helper.php
index c8fadbafc4c91..a101b0d2437ba 100644
--- a/enrol/lti/classes/helper.php
+++ b/enrol/lti/classes/helper.php
@@ -576,18 +576,19 @@ protected static function get_cartridge_parameters($toolid) {
// Work out the name of the tool.
$title = self::get_name($tool);
$launchurl = self::get_launch_url($toolid);
- $launchurl = $launchurl->out();
- $icon = self::get_icon($tool);
+ $launchurl = $launchurl->out(false);
+ $iconurl = self::get_icon($tool);
+ $iconurl = $iconurl->out(false);
$securelaunchurl = null;
- $secureicon = null;
+ $secureiconurl = null;
$vendorurl = new \moodle_url('/');
- $vendorurl = $vendorurl->out();
+ $vendorurl = $vendorurl->out(false);
$description = self::get_description($tool);
// If we are a https site, we can add the launch url and icon urls as secure equivalents.
if (\is_https()) {
$securelaunchurl = $launchurl;
- $secureicon = $icon;
+ $secureiconurl = $iconurl;
}
return array(
@@ -595,13 +596,13 @@ protected static function get_cartridge_parameters($toolid) {
"/blti:title" => $title,
"/blti:description" => $description,
"/blti:extensions" => array(
- "/lticm:property[@name='icon_url']" => $icon,
- "/lticm:property[@name='secure_icon_url']" => $secureicon
+ "/lticm:property[@name='icon_url']" => $iconurl,
+ "/lticm:property[@name='secure_icon_url']" => $secureiconurl
),
"/blti:launch_url" => $launchurl,
"/blti:secure_launch_url" => $securelaunchurl,
- "/blti:icon" => $icon,
- "/blti:secure_icon" => $secureicon,
+ "/blti:icon" => $iconurl,
+ "/blti:secure_icon" => $secureiconurl,
"/blti:vendor" => array(
"/lticp:code" => $SITE->shortname,
"/lticp:name" => $SITE->fullname,
@@ -634,7 +635,7 @@ protected static function set_xpath($xpath, $parameters, $prefix = '') {
if (is_null($value)) {
$node->parentNode->removeChild($node);
} else {
- $node->nodeValue = $value;
+ $node->nodeValue = s($value);
}
}
} else {
diff --git a/enrol/lti/db/upgrade.php b/enrol/lti/db/upgrade.php
index 7b5736b44a54d..21c0943f74529 100644
--- a/enrol/lti/db/upgrade.php
+++ b/enrol/lti/db/upgrade.php
@@ -66,5 +66,8 @@ function xmldb_enrol_lti_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/enrol/manual/amd/build/form-potential-user-selector.min.js b/enrol/manual/amd/build/form-potential-user-selector.min.js
index bf66147628b8b..393173d748330 100644
--- a/enrol/manual/amd/build/form-potential-user-selector.min.js
+++ b/enrol/manual/amd/build/form-potential-user-selector.min.js
@@ -1 +1 @@
-define(["jquery","core/ajax","core/templates","core/str"],function(a,b,c,d){var e=100;return{processResults:function(b,c){var d=[];return a.isArray(c)?(a.each(c,function(a,b){d.push({value:b.id,label:b._label})}),d):c},transport:function(f,g,h,i){var j,k=a(f).attr("courseid"),l=a(f).attr("userfields").split(",");"undefined"==typeof k&&(k="1");var m=a(f).attr("enrolid");"undefined"==typeof m&&(m=""),j=b.call([{methodname:"core_enrol_get_potential_users",args:{courseid:k,enrolid:m,search:g,searchanywhere:!0,page:0,perpage:e+1}}]),j[0].then(function(b){var f=[],g=0;return b.length<=e?(a.each(b,function(b,d){var e=d,g=[];a.each(l,function(a,b){"undefined"!=typeof d[b]&&""!==d[b]&&(e.hasidentity=!0,g.push(d[b]))}),e.identity=g.join(", "),f.push(c.render("enrol_manual/form-user-selector-suggestion",e))}),a.when.apply(a.when,f).then(function(){var c=arguments;a.each(b,function(a,b){b._label=c[g],g++}),h(b)})):d.get_string("toomanyuserstoshow","core",">"+e).then(function(a){h(a)})}).fail(i)}}});
\ No newline at end of file
+define(["jquery","core/ajax","core/templates","core/str"],function(a,b,c,d){return{processResults:function(b,c){var d=[];return a.isArray(c)?(a.each(c,function(a,b){d.push({value:b.id,label:b._label})}),d):c},transport:function(e,f,g,h){var i,j=a(e).attr("courseid"),k=a(e).attr("userfields").split(",");"undefined"==typeof j&&(j="1");var l=a(e).attr("enrolid");"undefined"==typeof l&&(l="");var m=parseInt(a(e).attr("perpage"));isNaN(m)&&(m=100),i=b.call([{methodname:"core_enrol_get_potential_users",args:{courseid:j,enrolid:l,search:f,searchanywhere:!0,page:0,perpage:m+1}}]),i[0].then(function(b){var e=[],f=0;return b.length<=m?(a.each(b,function(b,d){var f=d,g=[];a.each(k,function(a,b){"undefined"!=typeof d[b]&&""!==d[b]&&(f.hasidentity=!0,g.push(d[b]))}),f.identity=g.join(", "),e.push(c.render("enrol_manual/form-user-selector-suggestion",f))}),a.when.apply(a.when,e).then(function(){var c=arguments;a.each(b,function(a,b){b._label=c[f],f++}),g(b)})):d.get_string("toomanyuserstoshow","core",">"+m).then(function(a){g(a)})}).fail(h)}}});
\ No newline at end of file
diff --git a/enrol/manual/amd/src/form-potential-user-selector.js b/enrol/manual/amd/src/form-potential-user-selector.js
index 7fac602a91a36..c2e53d82fd516 100644
--- a/enrol/manual/amd/src/form-potential-user-selector.js
+++ b/enrol/manual/amd/src/form-potential-user-selector.js
@@ -25,9 +25,6 @@
define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax, Templates, Str) {
- /** @var {Number} Maximum number of users to show. */
- var MAXUSERS = 100;
-
return /** @alias module:enrol_manual/form-potential-user-selector */ {
processResults: function(selector, results) {
@@ -57,6 +54,10 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax,
if (typeof enrolid === "undefined") {
enrolid = '';
}
+ var perpage = parseInt($(selector).attr('perpage'));
+ if (isNaN(perpage)) {
+ perpage = 100;
+ }
promise = Ajax.call([{
methodname: 'core_enrol_get_potential_users',
@@ -66,7 +67,7 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax,
search: query,
searchanywhere: true,
page: 0,
- perpage: MAXUSERS + 1
+ perpage: perpage + 1
}
}]);
@@ -74,7 +75,7 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax,
var promises = [],
i = 0;
- if (results.length <= MAXUSERS) {
+ if (results.length <= perpage) {
// Render the label.
$.each(results, function(index, user) {
var ctx = user,
@@ -101,7 +102,7 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax,
});
} else {
- return Str.get_string('toomanyuserstoshow', 'core', '>' + MAXUSERS).then(function(toomanyuserstoshow) {
+ return Str.get_string('toomanyuserstoshow', 'core', '>' + perpage).then(function(toomanyuserstoshow) {
success(toomanyuserstoshow);
return;
});
diff --git a/enrol/manual/classes/enrol_users_form.php b/enrol/manual/classes/enrol_users_form.php
index 165a6e996de1a..5a4e50f54f114 100644
--- a/enrol/manual/classes/enrol_users_form.php
+++ b/enrol/manual/classes/enrol_users_form.php
@@ -99,6 +99,7 @@ public function definition() {
'multiple' => true,
'courseid' => $course->id,
'enrolid' => $instance->id,
+ 'perpage' => $CFG->maxusersperpage,
'userfields' => implode(',', get_extra_user_fields($context))
);
$mform->addElement('autocomplete', 'userlist', get_string('selectusers', 'enrol_manual'), array(), $options);
diff --git a/enrol/manual/db/upgrade.php b/enrol/manual/db/upgrade.php
index 48dfc6929bf63..0546271b635f0 100644
--- a/enrol/manual/db/upgrade.php
+++ b/enrol/manual/db/upgrade.php
@@ -39,5 +39,8 @@ function xmldb_enrol_manual_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/enrol/manual/tests/behat/quickenrolment.feature b/enrol/manual/tests/behat/quickenrolment.feature
index 2afa506adc372..72bb05926b64b 100644
--- a/enrol/manual/tests/behat/quickenrolment.feature
+++ b/enrol/manual/tests/behat/quickenrolment.feature
@@ -154,6 +154,16 @@ Feature: Teacher can search and enrol users one by one into the course
And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row"
Then I should see "Too many users (>100) to show"
+ @javascript
+ Scenario: Changing the Maximum users per page setting affects the enrolment pop-up.
+ Given the following config values are set as admin:
+ | maxusersperpage | 5 |
+ And I navigate to course participants
+ And I press "Enrol users"
+ When I set the field "Select users" to "student00"
+ And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row"
+ Then I should see "Too many users (>5) to show"
+
@javascript
Scenario: Change the Show user identity setting affects the enrolment pop-up.
Given I log out
diff --git a/enrol/mnet/db/upgrade.php b/enrol/mnet/db/upgrade.php
index f6d9efb4af0ac..62dd9bb04d31f 100644
--- a/enrol/mnet/db/upgrade.php
+++ b/enrol/mnet/db/upgrade.php
@@ -39,5 +39,8 @@ function xmldb_enrol_mnet_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/enrol/paypal/db/upgrade.php b/enrol/paypal/db/upgrade.php
index 93ebd504d81f6..40b8abda19e28 100644
--- a/enrol/paypal/db/upgrade.php
+++ b/enrol/paypal/db/upgrade.php
@@ -138,5 +138,8 @@ function xmldb_enrol_paypal_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/enrol/self/db/upgrade.php b/enrol/self/db/upgrade.php
index cb255e8bf6dd5..42046662970d4 100644
--- a/enrol/self/db/upgrade.php
+++ b/enrol/self/db/upgrade.php
@@ -39,5 +39,8 @@ function xmldb_enrol_self_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/enrol/self/lib.php b/enrol/self/lib.php
index bac388754b930..0f5d84435b0af 100644
--- a/enrol/self/lib.php
+++ b/enrol/self/lib.php
@@ -448,8 +448,9 @@ public function sync(progress_trace $trace, $courseid = null) {
$userid = $instance->userid;
unset($instance->userid);
$this->unenrol_user($instance, $userid);
- $days = $instance->customint2 / 60*60*24;
- $trace->output("unenrolling user $userid from course $instance->courseid as they have did not log in for at least $days days", 1);
+ $days = $instance->customint2 / DAYSECS;
+ $trace->output("unenrolling user $userid from course $instance->courseid " .
+ "as they did not log in for at least $days days", 1);
}
$rs->close();
@@ -465,8 +466,9 @@ public function sync(progress_trace $trace, $courseid = null) {
$userid = $instance->userid;
unset($instance->userid);
$this->unenrol_user($instance, $userid);
- $days = $instance->customint2 / 60*60*24;
- $trace->output("unenrolling user $userid from course $instance->courseid as they have did not access course for at least $days days", 1);
+ $days = $instance->customint2 / DAYSECS;
+ $trace->output("unenrolling user $userid from course $instance->courseid " .
+ "as they did not access the course for at least $days days", 1);
}
$rs->close();
diff --git a/enrol/self/tests/self_test.php b/enrol/self/tests/self_test.php
index 0a6fcffe03483..e939eaf4ca492 100644
--- a/enrol/self/tests/self_test.php
+++ b/enrol/self/tests/self_test.php
@@ -61,7 +61,7 @@ public function test_longtimnosee() {
$now = time();
- $trace = new null_progress_trace();
+ $trace = new progress_trace_buffer(new text_progress_trace(), false);
// Prepare some data.
@@ -133,18 +133,32 @@ public function test_longtimnosee() {
// Execute sync - this is the same thing used from cron.
$selfplugin->sync($trace, $course2->id);
+ $output = $trace->get_buffer();
+ $trace->reset_buffer();
$this->assertEquals(10, $DB->count_records('user_enrolments'));
-
+ $this->assertStringContainsString('No expired enrol_self enrolments detected', $output);
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user1->id)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user2->id)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user1->id)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user3->id)));
+
$selfplugin->sync($trace, null);
+ $output = $trace->get_buffer();
+ $trace->reset_buffer();
$this->assertEquals(6, $DB->count_records('user_enrolments'));
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user1->id)));
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user2->id)));
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user1->id)));
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user3->id)));
+ $this->assertStringContainsString('unenrolling user ' . $user1->id . ' from course ' . $course1->id .
+ ' as they did not log in for at least 14 days', $output);
+ $this->assertStringContainsString('unenrolling user ' . $user1->id . ' from course ' . $course3->id .
+ ' as they did not log in for at least 50 days', $output);
+ $this->assertStringContainsString('unenrolling user ' . $user2->id . ' from course ' . $course1->id .
+ ' as they did not access the course for at least 14 days', $output);
+ $this->assertStringContainsString('unenrolling user ' . $user3->id . ' from course ' . $course3->id .
+ ' as they did not access the course for at least 50 days', $output);
+ $this->assertStringNotContainsString('unenrolling user ' . $user4->id, $output);
$this->assertEquals(6, $DB->count_records('role_assignments'));
$this->assertEquals(4, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id)));
@@ -669,7 +683,7 @@ public function test_get_welcome_email_contact() {
$context = context_course::instance($course1->id);
// Get editing teacher role.
- $editingteacherrole = $DB->get_record('role', ['archetype' => 'editingteacher']);
+ $editingteacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
$this->assertNotEmpty($editingteacherrole);
// Enable self enrolment plugin and set to send email from course contact.
@@ -700,7 +714,7 @@ public function test_get_welcome_email_contact() {
$this->assertEquals($user1->email, $contact->email);
// Get manager role, and enrol user as manager.
- $managerrole = $DB->get_record('role', ['archetype' => 'manager']);
+ $managerrole = $DB->get_record('role', ['shortname' => 'manager']);
$this->assertNotEmpty($managerrole);
$instance1->customint4 = ENROL_SEND_EMAIL_FROM_KEY_HOLDER;
$DB->update_record('enrol', $instance1);
diff --git a/enrol/tests/externallib_test.php b/enrol/tests/externallib_test.php
index da07c87ab97c8..ee4ca4bba3bd6 100644
--- a/enrol/tests/externallib_test.php
+++ b/enrol/tests/externallib_test.php
@@ -958,6 +958,154 @@ public function test_edit_user_enrolment() {
$this->assertEquals(ENROL_USER_SUSPENDED, $ue->status);
}
+ /**
+ * dataProvider for test_submit_user_enrolment_form().
+ */
+ public function submit_user_enrolment_form_provider() {
+ $now = new DateTime();
+
+ $nextmonth = clone($now);
+ $nextmonth->add(new DateInterval('P1M'));
+
+ return [
+ 'Invalid data' => [
+ 'customdata' => [
+ 'status' => ENROL_USER_ACTIVE,
+ 'timestart' => [
+ 'day' => $now->format('j'),
+ 'month' => $now->format('n'),
+ 'year' => $now->format('Y'),
+ 'hour' => $now->format('G'),
+ 'minute' => 0,
+ 'enabled' => 1,
+ ],
+ 'timeend' => [
+ 'day' => $now->format('j'),
+ 'month' => $now->format('n'),
+ 'year' => $now->format('Y'),
+ 'hour' => $now->format('G'),
+ 'minute' => 0,
+ 'enabled' => 1,
+ ],
+ ],
+ 'expectedresult' => false,
+ 'validationerror' => true
+ ],
+ 'Valid data' => [
+ 'customdata' => [
+ 'status' => ENROL_USER_ACTIVE,
+ 'timestart' => [
+ 'day' => $now->format('j'),
+ 'month' => $now->format('n'),
+ 'year' => $now->format('Y'),
+ 'hour' => $now->format('G'),
+ 'minute' => 0,
+ 'enabled' => 1,
+ ],
+ 'timeend' => [
+ 'day' => $nextmonth->format('j'),
+ 'month' => $nextmonth->format('n'),
+ 'year' => $nextmonth->format('Y'),
+ 'hour' => $nextmonth->format('G'),
+ 'minute' => 0,
+ 'enabled' => 1,
+ ],
+ ],
+ 'expectedresult' => true,
+ 'validationerror' => false
+ ],
+ 'Suspend user' => [
+ 'customdata' => [
+ 'status' => ENROL_USER_SUSPENDED,
+ ],
+ 'expectedresult' => true,
+ 'validationerror' => false
+ ],
+ ];
+ }
+
+ /**
+ * @param array $customdata The data we are providing to the webservice.
+ * @param bool $expectedresult The result we are expecting to receive from the webservice.
+ * @param bool $validationerror The validationerror we are expecting to receive from the webservice.
+ * @dataProvider submit_user_enrolment_form_provider
+ */
+ public function test_submit_user_enrolment_form($customdata, $expectedresult, $validationerror) {
+ global $CFG, $DB;
+
+ $this->resetAfterTest(true);
+ $datagen = $this->getDataGenerator();
+
+ /** @var enrol_manual_plugin $manualplugin */
+ $manualplugin = enrol_get_plugin('manual');
+
+ $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST);
+ $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST);
+ $course = $datagen->create_course();
+ $user = $datagen->create_user();
+ $teacher = $datagen->create_user();
+
+ $instanceid = null;
+ $instances = enrol_get_instances($course->id, true);
+ foreach ($instances as $inst) {
+ if ($inst->enrol == 'manual') {
+ $instanceid = (int)$inst->id;
+ break;
+ }
+ }
+ if (empty($instanceid)) {
+ $instanceid = $manualplugin->add_default_instance($course);
+ if (empty($instanceid)) {
+ $instanceid = $manualplugin->add_instance($course);
+ }
+ }
+ $this->assertNotNull($instanceid);
+
+ $instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST);
+ $manualplugin->enrol_user($instance, $user->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE);
+ $manualplugin->enrol_user($instance, $teacher->id, $teacherroleid, 0, 0, ENROL_USER_ACTIVE);
+ $ueid = (int) $DB->get_field(
+ 'user_enrolments',
+ 'id',
+ ['enrolid' => $instance->id, 'userid' => $user->id],
+ MUST_EXIST
+ );
+
+ // Login as teacher.
+ $teacher->ignoresesskey = true;
+ $this->setUser($teacher);
+
+ $formdata = [
+ 'ue' => $ueid,
+ 'ifilter' => 0,
+ 'status' => null,
+ 'timestart' => null,
+ 'timeend' => null,
+ ];
+
+ $formdata = array_merge($formdata, $customdata);
+
+ require_once("$CFG->dirroot/enrol/editenrolment_form.php");
+ $formdata = enrol_user_enrolment_form::mock_generate_submit_keys($formdata);
+
+ $querystring = http_build_query($formdata, '', '&');
+
+ $result = external_api::clean_returnvalue(
+ core_enrol_external::submit_user_enrolment_form_returns(),
+ core_enrol_external::submit_user_enrolment_form($querystring)
+ );
+
+ $this->assertEquals(
+ ['result' => $expectedresult, 'validationerror' => $validationerror],
+ $result,
+ '', 0.0, 10, true);
+
+ if (!empty($result['result'])) {
+ $ue = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST);
+ $this->assertEquals($formdata['status'], $ue->status);
+ }
+ }
+
/**
* Test for core_enrol_external::unenrol_user_enrolment().
*/
diff --git a/favourites/tests/component_favourite_service_test.php b/favourites/tests/component_favourite_service_test.php
index 78c43d242e0c3..b4440073aaad9 100644
--- a/favourites/tests/component_favourite_service_test.php
+++ b/favourites/tests/component_favourite_service_test.php
@@ -88,7 +88,7 @@ protected function get_mock_repository(array $mockstore) {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
- if (array_diff($criteria, $mockrowarr) == []) {
+ if (array_diff_assoc($criteria, $mockrowarr) == []) {
$returns[$index] = $mockrow;
}
}
@@ -107,7 +107,7 @@ protected function get_mock_repository(array $mockstore) {
$crit = ['userid' => $userid, 'component' => $comp, 'itemtype' => $type, 'itemid' => $id, 'contextid' => $ctxid];
foreach ($mockstore as $fakerow) {
$fakerowarr = (array)$fakerow;
- if (array_diff($crit, $fakerowarr) == []) {
+ if (array_diff_assoc($crit, $fakerowarr) == []) {
return $fakerow;
}
}
@@ -133,7 +133,7 @@ protected function get_mock_repository(array $mockstore) {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
- if (array_diff($criteria, $mockrowarr) == []) {
+ if (array_diff_assoc($criteria, $mockrowarr) == []) {
$count++;
}
}
@@ -156,7 +156,7 @@ protected function get_mock_repository(array $mockstore) {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
- if (array_diff($criteria, $mockrowarr) == []) {
+ if (array_diff_assoc($criteria, $mockrowarr) == []) {
unset($mockstore[$index]);
}
}
@@ -169,7 +169,7 @@ protected function get_mock_repository(array $mockstore) {
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
echo "Here";
- if (array_diff($criteria, $mockrowarr) == []) {
+ if (array_diff_assoc($criteria, $mockrowarr) == []) {
return true;
}
}
diff --git a/favourites/tests/user_favourite_service_test.php b/favourites/tests/user_favourite_service_test.php
index c48e81feeac70..b4e4b61f66788 100644
--- a/favourites/tests/user_favourite_service_test.php
+++ b/favourites/tests/user_favourite_service_test.php
@@ -88,7 +88,7 @@ protected function get_mock_repository(array $mockstore) {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
- if (array_diff($criteria, $mockrowarr) == []) {
+ if (array_diff_assoc($criteria, $mockrowarr) == []) {
$returns[$index] = $mockrow;
}
}
@@ -107,7 +107,7 @@ protected function get_mock_repository(array $mockstore) {
$crit = ['userid' => $userid, 'component' => $comp, 'itemtype' => $type, 'itemid' => $id, 'contextid' => $ctxid];
foreach ($mockstore as $fakerow) {
$fakerowarr = (array)$fakerow;
- if (array_diff($crit, $fakerowarr) == []) {
+ if (array_diff_assoc($crit, $fakerowarr) == []) {
return $fakerow;
}
}
@@ -133,7 +133,7 @@ protected function get_mock_repository(array $mockstore) {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
- if (array_diff($criteria, $mockrowarr) == []) {
+ if (array_diff_assoc($criteria, $mockrowarr) == []) {
$count++;
}
}
@@ -156,7 +156,7 @@ protected function get_mock_repository(array $mockstore) {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
- if (array_diff($criteria, $mockrowarr) == []) {
+ if (array_diff_assoc($criteria, $mockrowarr) == []) {
return true;
}
}
diff --git a/files/converter/googledrive/classes/converter.php b/files/converter/googledrive/classes/converter.php
index aeda2ffbc6293..f55f8db05f201 100644
--- a/files/converter/googledrive/classes/converter.php
+++ b/files/converter/googledrive/classes/converter.php
@@ -124,7 +124,7 @@ public function start_document_conversion(\core_files\conversion $conversion) {
$uploadurl;
// Google returns a location header with the location for the upload.
foreach ($headers as $header) {
- if (strpos($header, 'Location:') === 0) {
+ if (stripos($header, 'Location:') === 0) {
$uploadurl = trim(substr($header, strpos($header, ':') + 1));
}
}
diff --git a/files/converter/unoconv/classes/converter.php b/files/converter/unoconv/classes/converter.php
index bbcedf0e73b30..cb20f607b2d50 100644
--- a/files/converter/unoconv/classes/converter.php
+++ b/files/converter/unoconv/classes/converter.php
@@ -194,7 +194,9 @@ public function serve_test_document() {
$conversions = conversion::get_conversions_for_file($testdocx, $format);
foreach ($conversions as $conversion) {
- $conversion->delete();
+ if ($conversion->get('id')) {
+ $conversion->delete();
+ }
}
$conversion = new conversion(0, (object) [
diff --git a/filter/activitynames/tests/filter_test.php b/filter/activitynames/tests/filter_test.php
index 403170efffe5a..b21c924c1b7d8 100644
--- a/filter/activitynames/tests/filter_test.php
+++ b/filter/activitynames/tests/filter_test.php
@@ -37,7 +37,6 @@
class filter_activitynames_filter_testcase extends advanced_testcase {
public function test_links() {
- global $CFG;
$this->resetAfterTest(true);
// Create a test course.
@@ -59,8 +58,8 @@ public function test_links() {
preg_match_all('~
([^<]*)~',
$filtered, $matches);
- // There should be 3 links links.
- $this->assertEquals(2, count($matches[1]));
+ // There should be 2 links links.
+ $this->assertCount(2, $matches[1]);
// Check text of title attribute.
$this->assertEquals($page1->name, $matches[1][0]);
@@ -74,4 +73,33 @@ public function test_links() {
$this->assertEquals($page1->name, $matches[3][0]);
$this->assertEquals($page2->name, $matches[3][1]);
}
+
+ public function test_links_activity_named_hyphen() {
+ $this->resetAfterTest(true);
+
+ // Create a test course.
+ $course = $this->getDataGenerator()->create_course();
+ $context = context_course::instance($course->id);
+
+ // Work around an issue with the activity names filter which maintains a static cache
+ // of activities for current course ID. We can re-build the cache by switching user.
+ $this->setUser($this->getDataGenerator()->create_user());
+
+ // Create a page activity named '-' (single hyphen).
+ $page = $this->getDataGenerator()->create_module('page', ['course' => $course->id, 'name' => '-']);
+
+ $html = '
Please read the - page.
';
+ $filtered = format_text($html, FORMAT_HTML, array('context' => $context));
+
+ // Find the page link in the filtered html.
+ preg_match_all('~
([^<]*)~',
+ $filtered, $matches);
+
+ // We should have exactly one match.
+ $this->assertCount(1, $matches[1]);
+
+ $this->assertEquals($page->name, $matches[1][0]);
+ $this->assertEquals($page->cmid, $matches[2][0]);
+ $this->assertEquals($page->name, $matches[3][0]);
+ }
}
diff --git a/filter/classes/external.php b/filter/classes/external.php
index ed6218f976304..07911a9ec5558 100644
--- a/filter/classes/external.php
+++ b/filter/classes/external.php
@@ -85,7 +85,7 @@ public static function get_available_in_context($contexts) {
} catch (Exception $e) {
$warnings[] = array(
'item' => 'context',
- 'itemid' => $context['instanceid'],
+ 'itemid' => $contextinfo['instanceid'],
'warningcode' => $e->getCode(),
'message' => $e->getMessage(),
);
diff --git a/filter/emoticon/filter.php b/filter/emoticon/filter.php
index 5f5b3ff5dc052..6b6651ddcaca4 100644
--- a/filter/emoticon/filter.php
+++ b/filter/emoticon/filter.php
@@ -104,14 +104,14 @@ protected function replace_emoticons($text) {
}
// Detect all zones that we should not handle (including the nested tags).
- $processing = preg_split('/(<\/?(?:span|script)[^>]*>)/is', $text, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ $processing = preg_split('/(<\/?(?:span|script|pre)[^>]*>)/is', $text, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
// Initialize the results.
$resulthtml = "";
$exclude = 0;
// Define the patterns that mark the start of the forbidden zones.
- $excludepattern = array('/^ FORMAT_HTML,
'expected' => '
(n)(n)' . $this->get_converted_content_for_emoticon('(n)'),
],
+ 'Basic pre should not be processed' => [
+ 'input' => '
(n)
',
+ 'format' => FORMAT_HTML,
+ 'expected' => '
(n)
',
+ ],
+ 'Nested pre should not be processed' => [
+ 'input' => '
(n)
(n)
',
+ 'format' => FORMAT_HTML,
+ 'expected' => '
(n)
(n)
',
+ ],
+ 'Nested pre should not be processed but following emoticon' => [
+ 'input' => '
(n)
(n)
(n)',
+ 'format' => FORMAT_HTML,
+ 'expected' => '
(n)
(n)
' . $this->get_converted_content_for_emoticon('(n)'),
+ ],
];
}
diff --git a/filter/mathjaxloader/db/upgrade.php b/filter/mathjaxloader/db/upgrade.php
index e4bb953f13d25..c93d3987a12d8 100644
--- a/filter/mathjaxloader/db/upgrade.php
+++ b/filter/mathjaxloader/db/upgrade.php
@@ -160,5 +160,8 @@ function xmldb_filter_mathjaxloader_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/filter/mathjaxloader/lang/en/filter_mathjaxloader.php b/filter/mathjaxloader/lang/en/filter_mathjaxloader.php
index cbe42bd153c0a..c3bbe43c41cf6 100644
--- a/filter/mathjaxloader/lang/en/filter_mathjaxloader.php
+++ b/filter/mathjaxloader/lang/en/filter_mathjaxloader.php
@@ -38,7 +38,7 @@
This can be useful to save on bandwidth or because of local proxy restrictions.
-To use a local installation of MathJax, first download the full MathJax library from http://www.mathjax.org/. Then install it on a web server. Finally update the MathJax filter settings httpurl and/or httpsurl to point to the local MathJax.js URL.';
+To use a local installation of MathJax, first download the full MathJax library from https://www.mathjax.org/. Then install it on a web server. Finally update the MathJax filter settings httpurl and/or httpsurl to point to the local MathJax.js URL.';
$string['mathjaxsettings'] = 'MathJax configuration';
$string['mathjaxsettings_desc'] = 'The default MathJax configuration should be appropriate for most users, but MathJax is highly configurable and any of the standard MathJax configuration options can be added here.';
$string['privacy:metadata'] = 'The MathJax plugin does not store any personal data.';
diff --git a/filter/mediaplugin/db/upgrade.php b/filter/mediaplugin/db/upgrade.php
index a8a43ac6634ef..b201df6afbcfb 100644
--- a/filter/mediaplugin/db/upgrade.php
+++ b/filter/mediaplugin/db/upgrade.php
@@ -44,5 +44,8 @@ function xmldb_filter_mediaplugin_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/filter/mediaplugin/styles.css b/filter/mediaplugin/styles.css
index 9a17d5b671d8e..c6ec054fbfd99 100644
--- a/filter/mediaplugin/styles.css
+++ b/filter/mediaplugin/styles.css
@@ -19,6 +19,14 @@
margin: auto;
}
+/* This is needed to display videos in an adequate size and without too much space
+ withing the specific mod assign table views. */
+.path-mod-assign .gradingtable .mediaplugin,
+.path-mod-assign .submissionsummarytable .mediaplugin {
+ width: 400px;
+ height: auto;
+}
+
/* Make media plugin behave properly in mod summaries and labels */
.mod-indent-outer .mediaplugin {
display: table-cell;
diff --git a/filter/multilang/filter.php b/filter/multilang/filter.php
index efb618f705b22..2e9bac35575ee 100644
--- a/filter/multilang/filter.php
+++ b/filter/multilang/filter.php
@@ -16,8 +16,7 @@
// along with Moodle. If not, see
.
/**
- * @package filter
- * @subpackage multilang
+ * @package filter_multilang
* @copyright Gaetan Frenoy
* @copyright 2004 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -39,6 +38,14 @@
// Following new syntax is not compatible with old one:
// one langanother language
+
+/**
+ * Implementation of the Moodle filter API for the Multi-lang filter.
+ *
+ * @copyright Gaetan Frenoy
+ * @copyright 2004 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
class filter_multilang extends moodle_text_filter {
function filter($text, array $options = array()) {
global $CFG;
@@ -60,7 +67,7 @@ function filter($text, array $options = array()) {
$search = '/(<(?:lang|span) lang="[a-zA-Z0-9_-]*".*?>.*?<\/(?:lang|span)>)(\s*<(?:lang|span) lang="[a-zA-Z0-9_-]*".*?>.*?<\/(?:lang|span)>)+/is';
}
- $result = preg_replace_callback($search, 'filter_multilang_impl', $text);
+ $result = preg_replace_callback($search, [$this, 'process_match'], $text);
if (is_null($result)) {
return $text; //error during regex processing (too many nested spans?)
@@ -68,44 +75,60 @@ function filter($text, array $options = array()) {
return $result;
}
}
-}
-function filter_multilang_impl($langblock) {
- global $CFG;
-
- $mylang = current_language();
- static $parentcache;
- if (!isset($parentcache)) {
- $parentcache = array();
- }
- if (!array_key_exists($mylang, $parentcache)) {
- $parentlang = get_parent_language($mylang);
- $parentcache[$mylang] = $parentlang;
- } else {
- $parentlang = $parentcache[$mylang];
- }
+ /**
+ * This is the callback used by the preg_replace_callback call above.
+ *
+ * @param array $langblock one of the matches from the regex match.
+ * @return string the replacement string (one of the possible translations).
+ */
+ protected function process_match(array $langblock): string {
+ $searchtosplit = '/<(?:lang|span)[^>]+lang="([a-zA-Z0-9_-]+)"[^>]*>(.*?)<\/(?:lang|span)>/is';
+
+ if (!preg_match_all($searchtosplit, $langblock[0], $rawlanglist)) {
+ // Skip malformed blocks.
+ return $langblock[0];
+ }
- $searchtosplit = '/<(?:lang|span)[^>]+lang="([a-zA-Z0-9_-]+)"[^>]*>(.*?)<\/(?:lang|span)>/is';
+ $langlist = array();
+ foreach ($rawlanglist[1] as $index => $lang) {
+ $lang = str_replace('-', '_', strtolower($lang)); // Normalize languages.
+ $langlist[$lang] = $rawlanglist[2][$index];
+ }
- if (!preg_match_all($searchtosplit, $langblock[0], $rawlanglist)) {
- //skip malformed blocks
- return $langblock[0];
- }
+ // Follow the stream of parent languages.
+ $lang = current_language();
+ do {
+ if (isset($langlist[$lang])) {
+ return $langlist[$lang];
+ }
+ } while ($lang = $this->get_parent_lang($lang));
- $langlist = array();
- foreach ($rawlanglist[1] as $index=>$lang) {
- $lang = str_replace('-','_',strtolower($lang)); // normalize languages
- $langlist[$lang] = $rawlanglist[2][$index];
+ // If we don't find a match, default to the first provided translation.
+ return array_shift($langlist);
}
- if (array_key_exists($mylang, $langlist)) {
- return $langlist[$mylang];
- } else if (array_key_exists($parentlang, $langlist)) {
- return $langlist[$parentlang];
- } else {
- $first = array_shift($langlist);
- return $first;
+ /**
+ * Puts some caching around get_parent_language().
+ *
+ * Also handle parent == 'en' in a way that works better for us.
+ *
+ * @param string $lang a Moodle language code, e.g. 'fr'.
+ * @return string the parent language.
+ */
+ protected function get_parent_lang(string $lang): string {
+ static $parentcache;
+ if (!isset($parentcache)) {
+ $parentcache = ['en' => ''];
+ }
+ if (!isset($parentcache[$lang])) {
+ $parentcache[$lang] = get_parent_language($lang);
+ // The standard get_parent_language method returns '' for parent == 'en'.
+ // That is less helpful for us, so change it back.
+ if ($parentcache[$lang] === '') {
+ $parentcache[$lang] = 'en';
+ }
+ }
+ return $parentcache[$lang];
}
}
-
-
diff --git a/filter/multilang/tests/filter_test.php b/filter/multilang/tests/filter_test.php
new file mode 100644
index 0000000000000..2dbefa2c8219b
--- /dev/null
+++ b/filter/multilang/tests/filter_test.php
@@ -0,0 +1,148 @@
+.
+
+/**
+ * Unit tests.
+ *
+ * @package filter_multilang
+ * @category test
+ * @copyright 2019 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * Tests for filter_multilang.
+ *
+ * @copyright 2019 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class filter_multilang_filter_testcase extends advanced_testcase {
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->resetAfterTest(true);
+
+ // Enable glossary filter at top level.
+ filter_set_global_state('multilang', TEXTFILTER_ON);
+ }
+
+ /**
+ * Setup parent language relationship.
+ *
+ * @param string $child the child language, e.g. 'fr_ca'.
+ * @param string $parent the parent language, e.g. 'fr'.
+ */
+ protected function setup_parent_language(string $child, string $parent) {
+ global $CFG;
+
+ $langfolder = $CFG->dataroot . '/lang/' . $child;
+ check_dir_exists($langfolder);
+ $langconfig = " [
+ 'English',
+ 'EnglishFrançais',
+ 'en',
+ ],
+ 'Basic case FR' => [
+ 'Français',
+ 'EnglishFrançais',
+ 'fr',
+ ],
+ 'Reversed input order EN' => [
+ 'English',
+ 'FrançaisEnglish',
+ 'en',
+ ],
+ 'Reversed input order EN' => [
+ 'Français',
+ 'FrançaisEnglish',
+ 'fr',
+ ],
+ 'Fallback to parent when child not present' => [
+ 'Français',
+ 'EnglishFrançais',
+ 'fr_ca', ['fr_ca' => 'fr']
+ ],
+ 'Both parent and child language present, using child' => [
+ 'Québécois',
+ 'Québécois
+ Français
+ English',
+ 'fr_ca', ['fr_ca' => 'fr'],
+ ],
+ 'Both parent and child language present, using parent' => [
+ 'Français',
+ 'Québécois
+ Français
+ English',
+ 'fr', ['fr_ca' => 'fr'],
+ ],
+ 'Both parent and child language present - reverse order, using child' => [
+ 'Québécois',
+ 'English
+ Français
+ Québécois',
+ 'fr_ca', ['fr_ca' => 'fr'],
+ ],
+ 'Both parent and child language present - reverse order, using parent' => [
+ 'Français',
+ 'English
+ Français
+ Québécois',
+ 'fr', ['fr_ca' => 'fr'],
+ ],
+ 'Fallback to parent when child not present when parent is en' => [
+ 'English',
+ 'DeutschEnglish',
+ 'en_us',
+ ],
+ ];
+ }
+
+ /**
+ * Tests the filtering of multi-language strings.
+ *
+ * @dataProvider multilang_testcases
+ *
+ * @param string $expectedoutput The expected filter output.
+ * @param string $input the input that is filtererd.
+ * @param string $targetlang the laguage to set as the current languge .
+ * @param array $parentlangs Array child lang => parent lang. E.g. ['es_co' => 'es', 'es_mx' => 'es'].
+ */
+ public function test_filtering($expectedoutput, $input, $targetlang, $parentlangs = []) {
+ global $SESSION;
+ $SESSION->forcelang = $targetlang;
+
+ foreach ($parentlangs as $child => $parent) {
+ $this->setup_parent_language($child, $parent);
+ }
+
+ $filtered = format_text($input, FORMAT_HTML, array('context' => context_system::instance()));
+ $this->assertEquals($expectedoutput, $filtered);
+ }
+}
diff --git a/filter/tests/external_test.php b/filter/tests/external_test.php
index 71bdef4d48f6c..17796a3b4d9b4 100644
--- a/filter/tests/external_test.php
+++ b/filter/tests/external_test.php
@@ -187,5 +187,14 @@ public function test_get_available_in_context_module() {
$this->assertEquals($firstfilter, $result['filters'][0]['filter']); // OK, the filter is enabled globally.
$this->assertEquals(TEXTFILTER_OFF, $result['filters'][0]['localstate']); // It is not available in this context.
$this->assertEquals(TEXTFILTER_ON, $result['filters'][0]['inheritedstate']); // In the parent context is available.
+
+ // Try user without permission, warning expected.
+ $user = $this->getDataGenerator()->create_user();
+ $this->setUser($user);
+ $result = external::get_available_in_context(array(array('contextlevel' => 'module', 'instanceid' => $forum->cmid)));
+ $result = external_api::clean_returnvalue(external::get_available_in_context_returns(), $result);
+ $this->assertNotEmpty($result['warnings']);
+ $this->assertEquals('context', $result['warnings'][0]['item']);
+ $this->assertEquals($forum->cmid, $result['warnings'][0]['itemid']);
}
}
diff --git a/filter/tex/db/upgrade.php b/filter/tex/db/upgrade.php
index ec40486e27dda..dae22573abd56 100644
--- a/filter/tex/db/upgrade.php
+++ b/filter/tex/db/upgrade.php
@@ -44,5 +44,8 @@ function xmldb_filter_tex_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/grade/grading/form/guide/db/upgrade.php b/grade/grading/form/guide/db/upgrade.php
index 290350d3cdd19..e9e73f4c461d5 100644
--- a/grade/grading/form/guide/db/upgrade.php
+++ b/grade/grading/form/guide/db/upgrade.php
@@ -49,5 +49,8 @@ function xmldb_gradingform_guide_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/grade/grading/form/guide/lang/en/gradingform_guide.php b/grade/grading/form/guide/lang/en/gradingform_guide.php
index 7499a4c41a335..9343b4aabdfdd 100644
--- a/grade/grading/form/guide/lang/en/gradingform_guide.php
+++ b/grade/grading/form/guide/lang/en/gradingform_guide.php
@@ -49,7 +49,7 @@
$string['definemarkingguide'] = 'Define marking guide';
$string['description'] = 'Description';
$string['descriptionmarkers'] = 'Description for Markers';
-$string['descriptionstudents'] = 'Description for Students';
+$string['descriptionstudents'] = 'Description for students';
$string['err_maxscoreisnegative'] = 'The max score is not valid, negative values are not allowed';
$string['err_maxscorenotnumeric'] = 'Criterion max score must be numeric';
$string['err_nocomment'] = 'Comment can not be empty';
diff --git a/grade/grading/form/rubric/db/upgrade.php b/grade/grading/form/rubric/db/upgrade.php
index e7e0bdf5c63fe..7b47339e44b7e 100644
--- a/grade/grading/form/rubric/db/upgrade.php
+++ b/grade/grading/form/rubric/db/upgrade.php
@@ -45,5 +45,8 @@ function xmldb_gradingform_rubric_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/grade/grading/form/rubric/lang/en/gradingform_rubric.php b/grade/grading/form/rubric/lang/en/gradingform_rubric.php
index d5951aec2f570..b799a66f122fb 100644
--- a/grade/grading/form/rubric/lang/en/gradingform_rubric.php
+++ b/grade/grading/form/rubric/lang/en/gradingform_rubric.php
@@ -53,8 +53,8 @@
$string['leveldefinition'] = 'Level {$a} definition';
$string['levelempty'] = 'Click to edit level';
$string['levelsgroup'] = 'Levels group';
-$string['lockzeropoints'] = 'Calculate grade based on the rubric having a minimum score of 0';
-$string['lockzeropoints_help'] = 'This setting only applies if the sum of the minimum number of points for each criterion is greater than 0. If ticked, the minimum achievable grade for the rubric will be greater than 0. If unticked, the minimum possible score for the rubric will be mapped to the minimum grade available for the activity (which is 0 unless a scale is used).';
+$string['lockzeropoints'] = 'Calculate grade having a minimum score of the minimum achievable grade for the rubric';
+$string['lockzeropoints_help'] = 'This setting only applies if the sum of the minimum number of points for each criterion is greater than 0. If ticked, the minimum achievable grade for the rubric will be the minimum achievable grade for the rubric. If unticked, the minimum possible score for the rubric will be mapped to the minimum grade available for the activity (which is 0 unless a scale is used).';
$string['name'] = 'Name';
$string['needregrademessage'] = 'The rubric definition was changed after this student had been graded. The student can not see this rubric until you check the rubric and update the grade.';
$string['pluginname'] = 'Rubric';
@@ -75,7 +75,7 @@
If a scale is used for grading, the score will be rounded and converted to the scale elements as if they were consecutive integers.
-This grade calculation may be changed by editing the form and ticking the box \'Calculate grade based on the rubric having a minimum score of 0\'.';
+This grade calculation may be changed by editing the form and ticking the box \'Calculate grade having a minimum score of the minimum achievable grade for the rubric\'.';
$string['rubricnotcompleted'] = 'Please choose something for each criterion';
$string['rubricoptions'] = 'Rubric options';
$string['rubricstatus'] = 'Current rubric status';
diff --git a/grade/grading/form/rubric/renderer.php b/grade/grading/form/rubric/renderer.php
index 4b510d4c507ae..6382662489195 100644
--- a/grade/grading/form/rubric/renderer.php
+++ b/grade/grading/form/rubric/renderer.php
@@ -435,7 +435,7 @@ protected function rubric_edit_options($mode, $options) {
switch ($option) {
case 'sortlevelsasc':
// Display option as dropdown
- $html .= html_writer::label(get_string($option, 'gradingform_rubric'), $attrs['id'], false, array('class' => 'label'));
+ $html .= html_writer::label(get_string($option, 'gradingform_rubric'), $attrs['id'], false);
$value = (int)(!!$value); // make sure $value is either 0 or 1
if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
$selectoptions = array(0 => get_string($option.'0', 'gradingform_rubric'), 1 => get_string($option.'1', 'gradingform_rubric'));
diff --git a/grade/grading/form/rubric/tests/behat/grade_calculation.feature b/grade/grading/form/rubric/tests/behat/grade_calculation.feature
index 687f1a49c7e2b..0e264b67ee248 100644
--- a/grade/grading/form/rubric/tests/behat/grade_calculation.feature
+++ b/grade/grading/form/rubric/tests/behat/grade_calculation.feature
@@ -23,12 +23,13 @@ Feature: Converting rubric score to grades
| activity | name | intro | course | idnumber | grade | advancedgradingmethod_submissions |
| assign | Test assignment 1 | Test | C1 | assign1 | | rubric |
When I log in as "teacher1"
+ And I change window size to "large"
And I am on "Course 1" course homepage with editing mode on
And I go to "Test assignment 1" advanced grading definition page
And I set the following fields to these values:
| Name | Assignment 1 rubric |
| Description | Rubric test description |
- | Calculate grade based on the rubric having a minimum score of 0 | |
+ | Calculate grade having a minimum score of the minimum achievable grade for the rubric | |
And I define the following rubric:
| Criterion 1 | Level 11 | 20 | Level 12 | 25 | Level 13 | 40 | Level 14 | 50 |
| Criterion 2 | Level 21 | 20 | Level 22 | 25 | Level 23 | 30 | | |
diff --git a/grade/grading/form/rubric/tests/behat/negative_points.feature b/grade/grading/form/rubric/tests/behat/negative_points.feature
index 33d0e1e0deb91..363bb6feea7e5 100644
--- a/grade/grading/form/rubric/tests/behat/negative_points.feature
+++ b/grade/grading/form/rubric/tests/behat/negative_points.feature
@@ -26,6 +26,7 @@ Feature: Rubrics can have levels with negative scores
And the following "activities" exist:
| activity | name | intro | course | idnumber | grade | advancedgradingmethod_submissions |
| assign | Test assignment 1 | Test | C1 | assign1 | 100 | rubric |
+ And I change window size to "large"
When I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I go to "Test assignment 1" advanced grading definition page
diff --git a/grade/grading/lib.php b/grade/grading/lib.php
index d2f57e9f63bab..386363844eccf 100644
--- a/grade/grading/lib.php
+++ b/grade/grading/lib.php
@@ -322,8 +322,10 @@ public function get_available_areas() {
}
} else if ($this->get_context()->contextlevel == CONTEXT_MODULE) {
- list($context, $course, $cm) = get_context_info_array($this->get_context()->id);
- return self::available_areas('mod_'.$cm->modname);
+ $modulecontext = $this->get_context();
+ $coursecontext = $modulecontext->get_course_context();
+ $cm = get_fast_modinfo($coursecontext->instanceid)->get_cm($modulecontext->instanceid);
+ return self::available_areas("mod_{$cm->modname}");
} else {
throw new coding_exception('Unsupported gradable area context level');
diff --git a/grade/lib.php b/grade/lib.php
index 7a976615b5be0..67857cb02fa56 100644
--- a/grade/lib.php
+++ b/grade/lib.php
@@ -986,7 +986,7 @@ function print_grade_page_head($courseid, $active_type, $active_plugin=null,
// Put a warning on all gradebook pages if the course has modules currently scheduled for background deletion.
require_once($CFG->dirroot . '/course/lib.php');
- if (course_modules_pending_deletion($courseid)) {
+ if (course_modules_pending_deletion($courseid, true)) {
\core\notification::add(get_string('gradesmoduledeletionpendingwarning', 'grades'),
\core\output\notification::NOTIFY_WARNING);
}
diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index 1b82a20ee6e3f..53741c4256729 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -767,7 +767,7 @@ public function get_left_rows($displayaverages) {
$fieldcell = new html_table_cell();
$fieldcell->attributes['class'] = 'userfield user' . $field;
$fieldcell->header = false;
- $fieldcell->text = $user->{$field};
+ $fieldcell->text = s($user->{$field});
$userrow->cells[] = $fieldcell;
}
diff --git a/grade/report/history/tests/behat/basic_functionality.feature b/grade/report/history/tests/behat/basic_functionality.feature
index 06a951883d7b6..1b1326a05d8fd 100644
--- a/grade/report/history/tests/behat/basic_functionality.feature
+++ b/grade/report/history/tests/behat/basic_functionality.feature
@@ -77,7 +77,7 @@ Feature: A teacher checks the grade history report in a course
| Student 2 | The greatest assignment ever | 50.00 | 70.00 | Teacher 2 |
| Student 2 | Rewarding assignment | 60.00 | 80.00 | Teacher 2 |
# Test filtering by assignment.
- And I click on "The greatest assignment ever" "option" in the "#id_itemid" "css_element"
+ And I set the field "Grade item" to "The greatest assignment ever"
And I press "Submit"
And the following should exist in the "gradereport_history" table:
| First name/Surname | Grade item | Original grade | Revised grade | Grader |
@@ -87,7 +87,7 @@ Feature: A teacher checks the grade history report in a course
| Student 1 | Rewarding assignment | | 60.00 | Teacher 1 |
| Student 1 | Rewarding assignment | 60.00 | 80.00 | Teacher 2 |
# Test filtering by grader.
- And I click on "Teacher 1" "option" in the "#id_grader" "css_element"
+ And I set the field "Grader" to "Teacher 1"
And I press "Submit"
And the following should exist in the "gradereport_history" table:
| First name/Surname | Grade item | Original grade | Revised grade | Grader |
diff --git a/grade/report/overview/db/upgrade.php b/grade/report/overview/db/upgrade.php
index 72726d8cf82c0..6efe5a2d4fd9b 100644
--- a/grade/report/overview/db/upgrade.php
+++ b/grade/report/overview/db/upgrade.php
@@ -54,5 +54,8 @@ function xmldb_gradereport_overview_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
+ // Automatically generated Moodle v3.7.0 release upgrade line.
+ // Put any upgrade step following this.
+
return true;
}
diff --git a/grade/report/singleview/classes/local/ui/dropdown_attribute.php b/grade/report/singleview/classes/local/ui/dropdown_attribute.php
index 50f1ce9966712..06b37e1aa674e 100644
--- a/grade/report/singleview/classes/local/ui/dropdown_attribute.php
+++ b/grade/report/singleview/classes/local/ui/dropdown_attribute.php
@@ -93,7 +93,8 @@ public function html() {
'value' => $option,
'selected' => $selected == $option
];
- }, array_keys($options))
+ }, array_keys($options)),
+ 'label' => get_string('gradefor', 'gradereport_singleview', $this->label),
);
return $OUTPUT->render_from_template('gradereport_singleview/dropdown_attribute', $context);
diff --git a/grade/report/singleview/templates/bulk_insert.mustache b/grade/report/singleview/templates/bulk_insert.mustache
index abe592ac131ab..3c8a88dd8f986 100644
--- a/grade/report/singleview/templates/bulk_insert.mustache
+++ b/grade/report/singleview/templates/bulk_insert.mustache
@@ -18,13 +18,13 @@
Bulk insert attribute.
}}
-
+
Ωστόσο, σε κάποιους εξυπηρετητές αυτό θα εμποδίσει τη λειτουργία όλων των σελιδών PHP (θα βλέπετε σφάλματα όταν ανοίγετε τις σελίδες), οπότε θα πρέπει να διαγράψετε το αρχείο .htaccess.
';
+$string['langdownloaderror'] = 'Δυστυχώς η γλώσσα «{$a}» δεν είναι εγκατεστημένη. Η εγκατάσταση θα συνεχιστεί στα αγγλικά.';
+$string['memorylimithelp'] = '
Το όριο μνήμης της PHP στον εξυπηρετητή σας είναι ορισμένο αυτή τη στιγμή στα {$a}.
+
+
Αυτό μπορεί να προκαλέσει προβλήματα μνήμης στο Moodle στη συνέχεια, ειδικά αν έχετε πολλά ενεργοποιημένα αρθρώματα και/ή πολλούς χρήστες.
+
+
Προτείνεται η ρύθμιση της PHP με μεγαλύτερο όριο, αν αυτό είναι δυνατό, π.χ. 40M. Υπάρχουν πολλοί τρόποι να το κάνετε αυτό, τους οποίους μπορείτε να δοκιμάσετε:
+
+- Αν έχετε τη δυνατότητα, κάνετε επαναμεταγλώττιση της PHP με την παράμετρο --enable-memory-limit. Αυτό θα επιτρέψει στο Moodle να ορίσει μόνο του το όριο μνήμης.
+- Αν έχετε πρόσβαση στο αρχείο php.ini, μπορείτε να αλλάξετε τη ρύθμιση memory_limit σε 40M. Αν δεν έχετε πρόσβαση ζητήστε από το διαχειριστή να το κάνει για εσάς.
+- Σε κάποιους εξυπηρετητές PHP μπορείτε να δημιουργήσετε ένα αρχείο .htaccess στο φάκελο του Moodle που να περιέχει την παρακάτω γραμμή:
+
php_value memory_limit 40M
+
Ωστόσο, σε κάποιους εξυπηρετητές αυτό θα εμποδίσει τη λειτουργία όλων των σελίδων PHP (θα βλέπετε σφάλματα όταν ανοίγετε τις σελίδες), οπότε θα πρέπει να διαγράψετε το αρχείο .htaccess.
+';
$string['paths'] = 'Διαδρομές';
$string['pathserrcreatedataroot'] = 'Ο Φάκελος δεδομένων ({$a->dataroot}) δεν μπορεί να δημιουργθεί από το πρόγραμμα εγκατάστασης.';
$string['pathshead'] = 'Επιβεβαίωση Διαδρομών';
$string['pathsrodataroot'] = 'Ο Φάκελος Δεδομένων δεν είναι εγγράψιμος.';
$string['pathsroparentdataroot'] = 'Ο γονικός φάκελος ({$a->parent}) δεν είναι εγγράψιμος. Ο φάκελος δεδομένων ({$a->dataroot}) δεν μπορεί να δημιουργθεί από το πρόγραμμα εγκατάστασης.';
-$string['pathssubadmindir'] = 'Κάποιοι λίγοι κεντρικοί υπολογιστές ιστού χρησιμοποιούν το /admin ως ειδική διεύθυνση URL για την πρόσβαση σε κάποιο πίνακα ελέγχου ή κάτι τέτοιο. Δυστυχώς αυτό έρχεται σε αντίθεση με την τυπική τοποθεσία των σελίδων διαχείρισης (admin) του Moodle. Αυτό μπορεί να διορθωθεί με την μετονομασία του admin φακέλου στην εγκατάστασή σας, και βάζοντας αυτό το καινούργιο όνομα εδώ. Για παράδειγμα:
moodleadmin. Αυτό θα διορθώσει όλους τους συνδέσμους με το admin στην διεύθυνσή τους σε όλη την εγκατάσταση του Moodle σας.';
-$string['pathssubdataroot'] = '
Ένας φάκελος όπου το Moodle θα αποθηκεύει όλα τα ανεβασμένα από τους χρήστες αρχεία.
Αυτος ο φάκελος θα πρέπει να είναι αναγνώσιμος ΚΑΙ ΕΓΓΡΑΨΙΜΟΣ από τον χρήστη του εξυπηρετητή ιστού (συνήθως \'nobody\' ή \'apache\').
Δεν πρέπει να είναι προσβάσιμος κατευθείαν από τον ιστό.
Αν ο φάκελος δεν υπάρχει, η διαδικασία εγκατάστασης θα προσπαθήσει να τον δημιουργήσει.
';
+$string['pathssubadmindir'] = 'Κάποιοι λίγοι κεντρικοί υπολογιστές ιστού χρησιμοποιούν το /admin ως ειδική διεύθυνση URL για την πρόσβαση σε κάποιο πίνακα ελέγχου ή κάτι τέτοιο. Δυστυχώς αυτό έρχεται σε αντίθεση με την τυπική τοποθεσία των σελίδων διαχείρισης (admin) του Moodle. Αυτό μπορεί να διορθωθεί με την μετονομασία του admin φακέλου στην εγκατάστασή σας, και βάζοντας αυτό το καινούργιο όνομα εδώ. Για παράδειγμα:
moodleadmin. Αυτό θα διορθώσει όλους τους συνδέσμους με το admin στην διεύθυνσή τους σε όλη την εγκατάσταση του Moodle σας.';
+$string['pathssubdataroot'] = '
Ένας φάκελος όπου το Moodle θα αποθηκεύει όλα τα ανεβασμένα από τους χρήστες αρχεία.
Αυτος ο φάκελος θα πρέπει να είναι αναγνώσιμος ΚΑΙ ΕΓΓΡΑΨΙΜΟΣ από τον χρήστη του εξυπηρετητή ιστού (συνήθως «nobody» ή «apache»).
Δεν πρέπει να είναι προσβάσιμος κατευθείαν από τον ιστό.
Αν ο φάκελος δεν υπάρχει, η διαδικασία εγκατάστασης θα προσπαθήσει να τον δημιουργήσει.
';
$string['pathssubdirroot'] = '
Η πλήρης διαδρομή του φακέλου που περιέχει τα αρχεία κώδικα του Moodle.
';
-$string['pathssubwwwroot'] = '
Η πλήρης διεύθυνση (ιστού) από την οποία θα γίνεται η πρόσβαση στο Moodle, δηλαδή η διεύθυνση που οι χρήστες θα εισάγουν στην γραμμή διεύθυνσης του περιηγητή, για να έχουν πρόσβαση στου Moodle.
+$string['pathssubwwwroot'] = '
Η πλήρης διεύθυνση από την οποία θα γίνεται η πρόσβαση στο Moodle, δηλαδή η διεύθυνση που οι χρήστες θα εισάγουν στην γραμμή διεύθυνσης του περιηγητή, για να έχουν πρόσβαση στου Moodle.
Δεν είναι δυνατόν να έχετε πρόβαση στο Moodle χρησιμοποιώντας πολλαπλές διευθύνσεις. Εάν ο ιστότοπος θα είναι προσβάσιμος μέσω πολλαπλών διευθύνσεων τότε επιλέξτε την ευκολότερη και εγκαταστήστε μια μόνιμη ανακατεύθυνση για καθεμία από τις άλλες διευθύνσεις.
Εάν ο ιστότοπός σας είναι προσβάσιμος τόσο από το Διαδίκτυο όσο και από ένα εσωτερικό δίκτυο (που συχνά λέγεται intranet) τότε χρησιμοποιήστε εδώ την δημόσια διεύθυνση.
Αν η τρέχουσα διεύθυνση δεν είναι σωστή, παρακαλούμε αλλάξτε την URL διεύθυνση στην γραμμή διευθύνσεων του περιηγητή σας και επανεκκινήστε την εγκατάσταση.
';
$string['pathsunsecuredataroot'] = 'Η τοποθεσία του Φάκελου Δεδομένων δεν είναι ασφαλής';
-$string['pathswrongadmindir'] = 'Ο Φάκελος Admin δεν υπάρχει';
+$string['pathswrongadmindir'] = 'Ο φάκελος Admin δεν υπάρχει';
$string['phpextension'] = 'Επέκταση {$a} της PHP';
$string['phpversion'] = 'Έκδοση της PHP';
$string['phpversionhelp'] = 'p>Το Moodle απαιτεί η έκδοση της PHP να είναι τουλάχιστον 5.6.5 ή 7.1 (η 7.0.x έχει κάποιους περιορισμούς στη μηχανή).
@@ -74,7 +85,7 @@
$string['welcomep20'] = 'Βλέπετε αυτή τη σελίδα γιατί εγκαταστήσατε και ξεκινήσατε με επιτυχία το πακέτο
{$a->packname} {$a->packversion} στον υπολογιστή σας. Συγχαρητήρια!';
$string['welcomep30'] = 'Αυτή η έκδοση/διανομή
{$a->installername} περιλαμβάνει τις εφαρμογές για τη δημιουργία ενός περιβάλλοντος μέσα στο οποίο θα λειτουργεί το
Moodle, ονομαστικά:';
$string['welcomep40'] = 'Το πακέτο περιλαμβάνει επίσης το
Moodle {$a->moodlerelease} ({$a->moodleversion}).';
-$string['welcomep50'] = 'Η χρήση όλων των εφαρμογών σε αυτό το πακέτο υπόκειται στις αντίστοιχες άδειες. Ολόκληρο το πακέτο
{$a->installername} είναι
λογισμικό ανοικτού κώδικα και διανέμεται με την
GPL άδεια.';
-$string['welcomep60'] = 'Οι παρακάτω σελίδες θα σας καθοδηγήσουν με εύκολα βήματα στην εγκατάσταση και ρύθμιση του
Moodle στον υπολογιστή σας. Μπορείτε να δεχθείτε τις προεπιλεγμένες ρυθμίσεις ή προαιρετικά, να τις τροποποιήσετε ανάλογα με τις ανάγκες σας.';
-$string['welcomep70'] = 'Πατήστε το κουμπί "Συνέχεια" για να συνεχίσετε με την εκγατάσταση του
Moodle.';
+$string['welcomep50'] = 'Η χρήση όλων των εφαρμογών σε αυτό το πακέτο υπόκειται στις αντίστοιχες άδειες. Ολόκληρο το πακέτο
{$a->installername} είναι
λογισμικό ανοικτού κώδικα και διανέμεται με την
GPL άδεια.';
+$string['welcomep60'] = 'Οι παρακάτω σελίδες θα σας καθοδηγήσουν με εύκολα βήματα στην εγκατάσταση και ρύθμιση του
Moodle στον Η/Υ σας. Μπορείτε να δεχθείτε τις προεπιλεγμένες ρυθμίσεις ή προαιρετικά, να τις τροποποιήσετε ανάλογα με τις ανάγκες σας.';
+$string['welcomep70'] = 'Πατήστε το κουμπί «Συνέχεια» για να συνεχίσετε με την εγκατάσταση του
Moodle.';
$string['wwwroot'] = 'Διεύθυνση ιστού';
diff --git a/install/lang/el_kids/langconfig.php b/install/lang/el_kids/langconfig.php
new file mode 100644
index 0000000000000..ef6e6b69c445a
--- /dev/null
+++ b/install/lang/el_kids/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'el';
+$string['thislanguage'] = 'Ελληνικά για παιδιά';
diff --git a/install/lang/el_uni/langconfig.php b/install/lang/el_uni/langconfig.php
new file mode 100644
index 0000000000000..d5cc284bb0934
--- /dev/null
+++ b/install/lang/el_uni/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'el';
+$string['thislanguage'] = 'Ελληνικά για σχολές';
diff --git a/install/lang/el_wp/admin.php b/install/lang/el_wp/admin.php
new file mode 100644
index 0000000000000..4421c5ad64bb5
--- /dev/null
+++ b/install/lang/el_wp/admin.php
@@ -0,0 +1,44 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['clianswerno'] = 'ο';
+$string['cliansweryes'] = 'ν';
+$string['cliincorrectvalueerror'] = 'Σφάλμα, λανθασμένη τιμή «{$a->value}» για το «{$a->option}»';
+$string['cliincorrectvalueretry'] = 'Λανθασμένη τιμή. Παρακαλούμε προσπαθήστε ξανά.';
+$string['clitypevalue'] = 'πληκτρολογήστε μια τιμή';
+$string['clitypevaluedefault'] = 'πληκτρολογήστε μια τιμή· πατήστε Enter για να χρησιμοποιήσετε τηνπροεπιλεγμένη τιμή ({$a})';
+$string['cliunknowoption'] = 'Μη αναγνωρίσιμες επιλογές: {$a}
+Παρακαλούμε χρησιμοποιήστε την επιλογή --βοήθεια';
+$string['cliyesnoprompt'] = 'πατήστε y (σημαίνει yes=ναι) ή πατήστε n (σημαίνει no=όχι)';
+$string['environmentrequireinstall'] = 'απαιτείται να εγκατασταθεί/ ενεργοποιηθεί';
+$string['environmentrequireversion'] = 'απαιτείται η έκδοση {$a->needed} ενώ εσείς έχετε την {$a->current}';
+$string['upgradekeyset'] = 'Κλειδί αναβάθμισης (αφήστε κενό για να μην το ορίσετε)';
diff --git a/install/lang/el_wp/error.php b/install/lang/el_wp/error.php
new file mode 100644
index 0000000000000..bf4b25dd8b6d7
--- /dev/null
+++ b/install/lang/el_wp/error.php
@@ -0,0 +1,50 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['cannotcreatedboninstall'] = '
Αδυναμία δημιουργίας βάσης δεδομένων.
Η βάση δεδομένων που προσδιορίστηκε δεν υπάρχει και ο χρήστης που δόθηκε δεν έχει δικαίωμα να δημιουργήσει την βάση δεδομένων.
Ο διαχειριστής του ιστοτόπου πρέπει να επαληθεύσει τις ρυθμίσεις της βάσης δεδομένων.
';
+$string['cannotcreatelangdir'] = 'Δε δημιουργήθηκε φάκελος γλώσσας.';
+$string['cannotcreatetempdir'] = 'Αδυναμία δημιουργίας προσωρινού φακέλου';
+$string['cannotdownloadcomponents'] = 'Δεν μπορεί να γίνει λήψη των στοιχείων λογισμικού';
+$string['cannotdownloadzipfile'] = 'Δεν μπορεί να γίνει λήψη του αρχείου ZIP.';
+$string['cannotfindcomponent'] = 'Δεν βρέθηκε το στοιχείο λογισμικού.';
+$string['cannotsavemd5file'] = 'Αδυναμία αποθήκευσης αρχείου md5.';
+$string['cannotsavezipfile'] = 'Αδυναμία αποθήκευσης συμπιεσμένου αρχείου';
+$string['cannotunzipfile'] = 'Αδυναμία αποσυμπίεσης αρχείου';
+$string['componentisuptodate'] = 'Το στοιχείο λογισμικού είναι ενημερωμένο.';
+$string['dmlexceptiononinstall'] = '
Παρουσιάστηκε σφάλμα βάσης δεδομένων [{$a->errorcode}].
{$a->debuginfo}
';
+$string['downloadedfilecheckfailed'] = 'Αποτυχία ελέγχου αρχείου που έγινε λήψη';
+$string['invalidmd5'] = 'Μη έγκυρο md5';
+$string['missingrequiredfield'] = 'Κάποιο απαιτούμενο πεδίο λείπει';
+$string['remotedownloaderror'] = '
Απέτυχε η λήψη του τμήματος στον εξυπηρετητή σας. Παρακαλούμε επιβεβαιώστε τις ρυθμίσεις του διακομιστή μεσολάβησης (proxy)· η επέκταση PHP cURL συνιστάται θερμά.
Πρέπει να κατεβάσετε το {$a->url} χειροκίνητα, να το αντιγράψετε στο «{$a->dest}» στον εξυπηρετητή σας και να το αποσυμπιέσετε εκεί.
';
+$string['wrongdestpath'] = 'Λανθασμένη διαδρομή προορισμού (πλήρες όνομα).';
+$string['wrongsourcebase'] = 'Λανθασμένη βάση πηγής URL.';
+$string['wrongzipfilename'] = 'Λανθασμένo όνομα αρχείου ZIP.';
diff --git a/install/lang/el_wp/install.php b/install/lang/el_wp/install.php
new file mode 100644
index 0000000000000..37efea7bbbe26
--- /dev/null
+++ b/install/lang/el_wp/install.php
@@ -0,0 +1,80 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['admindirname'] = 'Φάκελος διαχειριστή';
+$string['availablelangs'] = 'Λίστα διαθέσιμων πακέτων γλωσσών';
+$string['chooselanguagehead'] = 'Επιλογή γλώσσας';
+$string['chooselanguagesub'] = 'Παρακαλούμε, επιλέξτε γλώσσα για την εγκατάσταση. Αυτή η γλώσσα θα χρησιμοποιηθεί επίσης ως προεπιλεγμένη γλώσσα για τον ιστότοπο, αν και μπορεί να αλλάξει αργότερα.';
+$string['clialreadyconfigured'] = 'Το αρχείο ρυθμίσεων config.php υπάρχει ήδη. Χρησιμοποιήστε το admin/cli/install_database.php για να εγκαταστήσετε το Moodle για αυτόν τον ιστότοπο.';
+$string['clialreadyinstalled'] = 'Το αρχείο ρυθμίσεων config.php υπάρχει ήδη. Χρησιμοποιήστε το admin/cli/install_database.php για να αναβαθμίσετε το Moodle για αυτόν τον ιστότοπο.';
+$string['cliinstallheader'] = 'Moodle {$a} πρόγραμμα εγκατάστασης γραμμής εντολών';
+$string['databasehost'] = 'Κεντρικός Υπολογιστής Βάσης Δεδομένων';
+$string['databasename'] = 'Όνομα Βάσης Δεδομένων';
+$string['databasetypehead'] = 'Επιλογή οδηγού βάσης δεδομένων';
+$string['dataroot'] = 'Φάκελος δεδομένων';
+$string['datarootpermission'] = 'Άδεια φακέλων/καταλόγων δεδομένων';
+$string['dbprefix'] = 'Πρόθεμα πινάκων';
+$string['dirroot'] = 'Φάκελος Moodle';
+$string['environmenthead'] = 'Έλεγχος περιβάλλοντος...';
+$string['environmentsub2'] = 'Κάθε έκδοση Moodle έχει κάποια ελάχιστη απαίτηση σχετικά με την έκδοση της PHP και ενός αριθμού από αναγκαίες επεκτάσεις PHP.
+Ο πλήρης έλεγχος του περιβάλλοντος πραγματοποιείται πριν κάθε εγκατάσταση και αναβάθμιση. Παρακαλούμε επικοινωνήστε με τον διαχειριστή του εξυπηρετητή εάν δεν ξέρετε πως να εγκαταστήσετε νέα έκδοση της PHP ή να ενεργοποιήσετε επεκτάσεις της.';
+$string['errorsinenvironment'] = 'Ο έλεγχος του περιβάλλοντος απέτυχε!';
+$string['installation'] = 'Εγκατάσταση';
+$string['langdownloaderror'] = 'Δυστυχώς η γλώσσα «{$a}» δεν είναι εγκατεστημένη. Η εγκατάσταση θα συνεχιστεί στα αγγλικά.';
+$string['memorylimithelp'] = '
Το όριο μνήμης της PHP στον εξυπηρετητή σας είναι ορισμένο αυτή τη στιγμή στα {$a}.
Αυτό μπορεί να προκαλέσει προβλήματα μνήμης στο Moodle στη συνέχεια, ειδικά αν έχετε πολλά ενεργοποιημένα αρθρώματα και/ή πολλούς χρήστες.
Προτείνεται η ρύθμιση της PHP με μεγαλύτερο όριο, αν αυτό είναι δυνατό, π.χ. 40M. Υπάρχουν πολλοί τρόποι να το κάνετε αυτό, τους οποίους μπορείτε να δοκιμάσετε:
- Αν έχετε τη δυνατότητα, κάνετε επαναμεταγλώττιση την PHP με την παράμετρο --enable-memory-limit. Αυτό θα επιτρέψει στο Moodle να ορίσει μόνο του το όριο μνήμης.
- Αν έχετε πρόσβαση στο αρχείο php.ini, μπορείτε να αλλάξετε τη ρύθμιση memory_limit σε 40M. Αν δεν έχετε πρόσβαση ζητήστε από το διαχειριστή να το κάνει για εσάς.
- Σε κάποιους εξυπηρετητές PHP μπορείτε να δημιουργήσετε ένα αρχείο .htaccess στο φάκελο του Moodle που να περιέχει τις παρακάτω γραμμές:
php_value memory_limit 40M
Ωστόσο, σε κάποιους εξυπηρετητές αυτό θα εμποδίσει τη λειτουργία όλων των σελιδών PHP (θα βλέπετε σφάλματα όταν ανοίγετε τις σελίδες), οπότε θα πρέπει να διαγράψετε το αρχείο .htaccess.
';
+$string['paths'] = 'Διαδρομές';
+$string['pathserrcreatedataroot'] = 'Ο Φάκελος δεδομένων ({$a->dataroot}) δεν μπορεί να δημιουργθεί από το πρόγραμμα εγκατάστασης.';
+$string['pathshead'] = 'Επιβεβαίωση Διαδρομών';
+$string['pathsrodataroot'] = 'Ο Φάκελος Δεδομένων δεν είναι εγγράψιμος.';
+$string['pathsroparentdataroot'] = 'Ο γονικός φάκελος ({$a->parent}) δεν είναι εγγράψιμος. Ο φάκελος δεδομένων ({$a->dataroot}) δεν μπορεί να δημιουργθεί από το πρόγραμμα εγκατάστασης.';
+$string['pathssubadmindir'] = 'Κάποιοι λίγοι κεντρικοί υπολογιστές ιστού χρησιμοποιούν το /admin ως ειδική διεύθυνση URL για την πρόσβαση σε κάποιο πίνακα ελέγχου ή κάτι τέτοιο. Δυστυχώς αυτό έρχεται σε αντίθεση με την τυπική τοποθεσία των σελίδων διαχείρισης (admin) του Moodle. Αυτό μπορεί να διορθωθεί με την μετονομασία του admin φακέλου στην εγκατάστασή σας, και βάζοντας αυτό το καινούργιο όνομα εδώ. Για παράδειγμα:
moodleadmin. Αυτό θα διορθώσει όλους τους συνδέσμους με το admin στην διεύθυνσή τους σε όλη την εγκατάσταση του Moodle σας.';
+$string['pathssubdataroot'] = '
Ένας φάκελος όπου το Moodle θα αποθηκεύει όλα τα ανεβασμένα από τους χρήστες αρχεία.
Αυτος ο φάκελος θα πρέπει να είναι αναγνώσιμος ΚΑΙ ΕΓΓΡΑΨΙΜΟΣ από τον χρήστη του εξυπηρετητή ιστού (συνήθως «nobody» ή «apache»).
Δεν πρέπει να είναι προσβάσιμος κατευθείαν από τον ιστό.
Αν ο φάκελος δεν υπάρχει, η διαδικασία εγκατάστασης θα προσπαθήσει να τον δημιουργήσει.
';
+$string['pathssubdirroot'] = '
Η πλήρης διαδρομή του φακέλου που περιέχει τα αρχεία κώδικα του Moodle.
';
+$string['pathssubwwwroot'] = '
Η πλήρης διεύθυνση (ιστού) από την οποία θα γίνεται η πρόσβαση στο Moodle, δηλαδή η διεύθυνση που οι χρήστες θα εισάγουν στην γραμμή διεύθυνσης του περιηγητή, για να έχουν πρόσβαση στου Moodle.
+
Δεν είναι δυνατόν να έχετε πρόβαση στο Moodle χρησιμοποιώντας πολλαπλές διευθύνσεις. Εάν ο ιστότοπος θα είναι προσβάσιμος μέσω πολλαπλών διευθύνσεων τότε επιλέξτε την ευκολότερη και εγκαταστήστε μια μόνιμη ανακατεύθυνση για καθεμία από τις άλλες διευθύνσεις.
+
Εάν ο ιστότοπός σας είναι προσβάσιμος τόσο από το Διαδίκτυο όσο και από ένα εσωτερικό δίκτυο (που συχνά λέγεται intranet) τότε χρησιμοποιήστε εδώ την δημόσια διεύθυνση.
+
Αν η τρέχουσα διεύθυνση δεν είναι σωστή, παρακαλούμε αλλάξτε την URL διεύθυνση στην γραμμή διευθύνσεων του περιηγητή σας και επανεκκινήστε την εγκατάσταση.
';
+$string['pathsunsecuredataroot'] = 'Η τοποθεσία του Φάκελου Δεδομένων δεν είναι ασφαλής';
+$string['pathswrongadmindir'] = 'Ο Φάκελος Admin δεν υπάρχει';
+$string['phpextension'] = 'Επέκταση {$a} της PHP';
+$string['phpversion'] = 'Έκδοση της PHP';
+$string['phpversionhelp'] = 'p>Το Moodle απαιτεί η έκδοση της PHP να είναι τουλάχιστον 5.6.5 ή 7.1 (η 7.0.x έχει κάποιους περιορισμούς στη μηχανή).
+
Αυτή τη στιγμή έχετε την έκδοση {$a}
+
Πρέπει να αναβαθμίσετε την PHP ή να μεταφερθείτε σε έναν κεντρικό Η/Υ με μια νεότερη έκδοση της PHP!
';
+$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
+$string['welcomep20'] = 'Βλέπετε αυτή τη σελίδα γιατί εγκαταστήσατε και ξεκινήσατε με επιτυχία το πακέτο
{$a->packname} {$a->packversion} στον υπολογιστή σας. Συγχαρητήρια!';
+$string['welcomep30'] = 'Αυτή η έκδοση/διανομή
{$a->installername} περιλαμβάνει τις εφαρμογές για τη δημιουργία ενός περιβάλλοντος μέσα στο οποίο θα λειτουργεί το
Moodle, ονομαστικά:';
+$string['welcomep40'] = 'Το πακέτο περιλαμβάνει επίσης το
Moodle {$a->moodlerelease} ({$a->moodleversion}).';
+$string['welcomep50'] = 'Η χρήση όλων των εφαρμογών σε αυτό το πακέτο υπόκειται στις αντίστοιχες άδειες. Ολόκληρο το πακέτο
{$a->installername} είναι
λογισμικό ανοικτού κώδικα και διανέμεται με την
GPL άδεια.';
+$string['welcomep60'] = 'Οι παρακάτω σελίδες θα σας καθοδηγήσουν με εύκολα βήματα στην εγκατάσταση και ρύθμιση του
Moodle στον υπολογιστή σας. Μπορείτε να δεχθείτε τις προεπιλεγμένες ρυθμίσεις ή προαιρετικά, να τις τροποποιήσετε ανάλογα με τις ανάγκες σας.';
+$string['welcomep70'] = 'Πατήστε το κουμπί «Συνέχεια» για να συνεχίσετε με την εγκατάσταση του
Moodle.';
+$string['wwwroot'] = 'Διεύθυνση ιστού';
diff --git a/install/lang/el_wp/langconfig.php b/install/lang/el_wp/langconfig.php
new file mode 100644
index 0000000000000..adb05a695894c
--- /dev/null
+++ b/install/lang/el_wp/langconfig.php
@@ -0,0 +1,35 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'el';
+$string['thisdirection'] = 'ltr';
+$string['thislanguage'] = 'Ελληνικά για χώρους εργασίας';
diff --git a/install/lang/el_wp/moodle.php b/install/lang/el_wp/moodle.php
new file mode 100644
index 0000000000000..6375cf9547e46
--- /dev/null
+++ b/install/lang/el_wp/moodle.php
@@ -0,0 +1,37 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['language'] = 'Γλώσσα';
+$string['moodlelogo'] = 'Λογότυπο Moodle';
+$string['next'] = 'Επόμενο';
+$string['previous'] = 'Προηγούμενο';
+$string['reload'] = 'Eπαναφόρτωση';
diff --git a/install/lang/en/install.php b/install/lang/en/install.php
index 974ece35dc5b5..4fcf862f92375 100644
--- a/install/lang/en/install.php
+++ b/install/lang/en/install.php
@@ -99,10 +99,7 @@
$string['welcomep30'] = 'This release of the
{$a->installername} includes the applications
to create an environment in which
Moodle will operate, namely:';
$string['welcomep40'] = 'The package also includes
Moodle {$a->moodlerelease} ({$a->moodleversion}).';
-$string['welcomep50'] = 'The use of all the applications in this package is governed by their respective
- licences. The complete
{$a->installername} package is
-
open source and is distributed
- under the
GPL license.';
+$string['welcomep50'] = 'The use of all the applications in this package is governed by their respective licences. The complete
{$a->installername} package is
open source and is distributed under the
GPL license.';
$string['welcomep60'] = 'The following pages will lead you through some easy to follow steps to
configure and set up
Moodle on your computer. You may accept the default
settings or, optionally, amend them to suit your own needs.';
diff --git a/install/lang/es_mx/install.php b/install/lang/es_mx/install.php
index 272628e4a1134..275e453fad968 100644
--- a/install/lang/es_mx/install.php
+++ b/install/lang/es_mx/install.php
@@ -92,10 +92,7 @@
$string['welcomep20'] = 'Si está viendo esta página es porque ha podido instalar y ejecutar exitosamente el paquete
{$a->packname} {$a->packversion} en su computadora. !Enhorabuena!';
$string['welcomep30'] = 'Esta versión de
{$a->installername} incluye las aplicaciones necesarias para que
Moodle funcione en su computadora, principalmente:';
$string['welcomep40'] = 'El paquete también incluye
Moodle {$a->moodlerelease} ({$a->moodleversion}).';
-$string['welcomep50'] = 'El uso de todas las aplicaciones del paquete está gobernado por sus respectivas
- licencias. El programa
{$a->installername} es
-
código abierto y se distribuye
- bajo licencia
GPL.';
+$string['welcomep50'] = 'El uso de todas las aplicaciones en este paquete está gobernado por sus respectivas licencias. El paquete completo
{$a->installername} es
código abierto y se distribuye bajo licencia
GPL.';
$string['welcomep60'] = 'Las siguientes páginas le guiarán a través de algunos sencillos pasos para configurar y ajustar
Moodle en su computadora. Puede utilizar los valores por defecto sugeridos o, de forma opcional, modificarlos para que se ajusten a sus necesidades.';
$string['welcomep70'] = 'Pulse en el botón "Siguiente" para continuar con la configuración de
Moodle.';
$string['wwwroot'] = 'Dirección Web';
diff --git a/install/lang/es_ve/langconfig.php b/install/lang/es_ve/langconfig.php
index 65aaeb6d25c67..12bed67bc5b81 100644
--- a/install/lang/es_ve/langconfig.php
+++ b/install/lang/es_ve/langconfig.php
@@ -31,4 +31,4 @@
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = 'es';
-$string['thislanguage'] = 'Español Venezuela';
+$string['thislanguage'] = 'Español - Venezuela';
diff --git a/install/lang/es_wp/langconfig.php b/install/lang/es_wp/langconfig.php
index 9f05ce4297f9c..a0d7bfeac591b 100644
--- a/install/lang/es_wp/langconfig.php
+++ b/install/lang/es_wp/langconfig.php
@@ -31,4 +31,5 @@
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = 'es';
+$string['thisdirection'] = 'ltr';
$string['thislanguage'] = 'Español para la Empresa';
diff --git a/install/lang/eu/error.php b/install/lang/eu/error.php
index 89f24daabae01..91dda3f407606 100644
--- a/install/lang/eu/error.php
+++ b/install/lang/eu/error.php
@@ -46,7 +46,7 @@
$string['downloadedfilecheckfailed'] = 'Jaitsitako fitxategiaren egiaztatzeak huts egin du.';
$string['invalidmd5'] = 'Kontrolerako aldagaia gaizki zegoen - saiatu berriz ere';
$string['missingrequiredfield'] = 'Beharrezko eremuren bat falta da.';
-$string['remotedownloaderror'] = '
Errorea osagaia zure zerbitzarian jaistean, mesedez egiaztatu proxy-ezarpenak, PHP cURL luzapena erabat gomendatzen da.
+$string['remotedownloaderror'] = '
Errorea osagaia zure zerbitzarian jaistean, mesedez egiaztatu proxy-ezarpenak, PHP cURL hedapena erabat gomendatzen da.
{$a->url} fitxategia eskuz jaitsi beharko zenuke, zure zerbitzariko "{$a->dest}"-ra kopiatu eta bertan deskonprimatu.
';
$string['wrongdestpath'] = 'Bide desegokia';
$string['wrongsourcebase'] = 'URL iturriaren oinarri akastuna';
diff --git a/install/lang/eu/install.php b/install/lang/eu/install.php
index f7ba951039234..fc656c2fd5f81 100644
--- a/install/lang/eu/install.php
+++ b/install/lang/eu/install.php
@@ -45,7 +45,7 @@
$string['dbprefix'] = 'Taulen aurrizkia';
$string['dirroot'] = 'Moodle direktorioa';
$string['environmenthead'] = 'Zure ingurunea egiaztatzen...';
-$string['environmentsub2'] = 'Moodle-ko bertsio bakoitzak PHPko gutxieneko bertsioa eta derrigorrez instalatu beharreko PHP luzapen batzuk ditu. Ingurunearen azterketa oso bat egiten da instalazioa eta eguneraketa bakoitza egin aurretik. Mesedez, jarri harremanetan zerbitzariaren kudeatzailearekin ez badakizu bertsio berria edo PHP luzapenak nola instalatu.';
+$string['environmentsub2'] = 'Moodle-ko bertsio bakoitzak PHPko gutxieneko bertsioa eta derrigorrez instalatu beharreko PHP hedapen batzuk ditu. Ingurunearen azterketa oso bat egiten da instalazioa eta eguneraketa bakoitza egin aurretik. Mesedez, jarri harremanetan zerbitzariaren kudeatzailearekin ez badakizu bertsio berria edo PHP hedapenak nola instalatu.';
$string['errorsinenvironment'] = 'Huts egin du ingurunearen egiaztatzeak!';
$string['installation'] = 'Instalazioa';
$string['langdownloaderror'] = 'Zoritxarrez "{$a}" hizkuntza ezin izan da jaitsi. Instalazio-prozesuak ingelesez jarraituko du.';
@@ -76,14 +76,14 @@
Direktorio honetan web-zerbitzariaren erabiltzaileak irakurtzeko eta idazteko baimena izan beharko ditu (normalean \'www-data\', \'nobody\', edo \'apache\').
Ez litzateke web bidez eskuragarri egon beharko.
Direktorioa existitzen ez bada, instalazioan sortzeko saiakera egingo da.
';
-$string['pathssubdirroot'] = '
Moodle-ko kodea daukan direktorioaren helbide osoa.
';
+$string['pathssubdirroot'] = '
Moodle-ko kodea daukan direktorioaren bide osoa.
';
$string['pathssubwwwroot'] = '
Moodle eskuragarri egongo den helbide osoa, hau da, erabiltzaileek Moodle-n sartzeko nabigatzaileareko helbide barran idatziko duten helbidea
Moodle ezin da hainbat helbidetatik eskuragarri egon. Zure gunea hainbat helbidetatik eskuragarri badago errazena aukeratu eta bertara beste helbideetatik behin-betiko berbideraketak konfiguratu itzazu.
Zure gunea Internetetik eta barne-sare batetik eskuragarri badago (batzuetan Intranet deitutakoa), hemen helbide publikoa erabili ezazu.
Oraingo helbidea egokia ez bada, mesedez aldatu ezazu URLa zure nabigatzailean eta instalazioa berriz abiatu ezazu.
';
$string['pathsunsecuredataroot'] = 'Dataroot-en kokapena ez da segurua';
$string['pathswrongadmindir'] = 'Admin direktorioa ez da existitzen';
-$string['phpextension'] = '{$a} PHP luzapena';
+$string['phpextension'] = '{$a} PHP hedapena';
$string['phpversion'] = 'PHP bertsioa';
$string['phpversionhelp'] = '
Moodle-k PHP 5.6.5 edo 7.1 bertsioetako bat behar du (7.0.x bertsioek muga batzuk dituzte).
Zure bertsioa: {$a}
@@ -93,10 +93,7 @@
$string['welcomep30'] = '
{$a->installername}ren bertsio honek
Moodle-k
zure ordenagailuan funtzionatzeko behar diren aplikazioak dauzka, zehazki hurrengoak:';
$string['welcomep40'] = 'Paketeak ere zera dauka:
Moodle {$a->moodlerelease} ({$a->moodleversion}).';
-$string['welcomep50'] = 'Paketeko aplikazio guztien erabilpena dagozkien lizentziek
- arautzen dute.
{$a->installername} aplikazioak
-
kode irekia dauka eta
-
GPL lizentziapean banatzen da.';
+$string['welcomep50'] = 'Paketeko aplikazio guztien erabilpena dagozkien lizentziek arautzen dute.
{$a->installername} aplikazioak
kode irekia dauka eta
GPL lizentziapean banatzen da.';
$string['welcomep60'] = 'Datozen orriek urrats erraz batzuen bidez gidatuko zaituzte
Moodle zure ordenagailuan instalatu eta konfiguratzeko. Aholkatzen diren lehenetsitako balioak mantendu edo, nahi izanez gero, alda ditzakezu zure beharrei erantzun diezaieten.';
$string['welcomep70'] = 'Egin klik "Hurrengoa" botoian
Moodleren konfigurazioarekin jarraitzeko.';
$string['wwwroot'] = 'Web helbidea';
diff --git a/install/lang/fr/install.php b/install/lang/fr/install.php
index dd55efbe1a5a8..6104329f3feea 100644
--- a/install/lang/fr/install.php
+++ b/install/lang/fr/install.php
@@ -44,11 +44,11 @@
$string['datarootpermission'] = 'Droits d\'accès au dossier de données';
$string['dbprefix'] = 'Préfixe des tables';
$string['dirroot'] = 'Dossier Moodle';
-$string['environmenthead'] = 'Vérification de l\'environnement...';
+$string['environmenthead'] = 'Vérification de l\'environnement…';
$string['environmentsub2'] = 'Chaque version de Moodle nécessite une version minimale de certains composants PHP et des extensions de PHP obligatoires. Une vérification complète de l\'environnement est effectuée avec chaque installation et chaque mise à jour. Veuillez contacter l\'administrateur du serveur si vous ne savez pas comment installer une nouvelle version ou activer des extensions de PHP.';
$string['errorsinenvironment'] = 'Échec de la vérification de l\'environnement !';
$string['installation'] = 'Installation';
-$string['langdownloaderror'] = 'La langue {$a} n\'a pas pu être téléchargée. La suite de l\'installation se déroulera en anglais. Vous pourrez télécharger et installer d\'autres langues à la fin de l\'installation';
+$string['langdownloaderror'] = 'La langue « {$a} » n\'a pas pu être téléchargée. La suite de l\'installation se déroulera en anglais. Vous pourrez télécharger et installer d\'autres langues à la fin de l\'installation';
$string['memorylimithelp'] = '
La limite de mémoire de PHP sur votre serveur est actuellement de {$a}.
Cette valeur trop basse risque de générer des problèmes de manque de mémoire pour Moodle, notamment si vous utilisez beaucoup de modules et/ou si vous avez un grand nombre d\'utilisateurs.
Il est recommandé de configurer PHP avec une limite de mémoire aussi élevée que possible, par exemple 40 Mo. Vous pouvez obtenir cela de différentes façons :
@@ -85,7 +85,7 @@
$string['welcomep20'] = 'Vous voyez cette page, car vous avez installé Moodle correctement et lancé le logiciel
{$a->packname} {$a->packversion} sur votre ordinateur. Félicitations !';
$string['welcomep30'] = 'Cette version de
{$a->installername} comprend des logiciels qui créent un environnement dans lequel
Moodle va fonctionner, à savoir :';
$string['welcomep40'] = 'Ce paquet contient également
Moodle {$a->moodlerelease} ({$a->moodleversion}).';
-$string['welcomep50'] = 'L\'utilisation de tous les logiciels de ce paquet est soumis à l\'acceptation de leurs licences respectives. Le paquet
{$a->installername} est un
logiciel libre. Il est distribué sous licence
GPL.';
+$string['welcomep50'] = 'L\'utilisation de tous les logiciels de ce paquetage est soumis à l\'acceptation de leurs licences respectives. Le paquetage complet
{$a->installername} est un
logiciel libre. Il est distribué sous licence
GPL.';
$string['welcomep60'] = 'Les pages suivantes vous aideront pas à pas à configurer et mettre en place
Moodle sur votre ordinateur. Il vous sera possible d\'accepter les réglages par défaut ou, facultativement, de les adapter à vos propres besoins.';
$string['welcomep70'] = 'Cliquer sur le bouton « Suivant » ci-dessous pour continuer l\'installation de
Moodle.';
$string['wwwroot'] = 'Adresse web';
diff --git a/install/lang/fr_incl/langconfig.php b/install/lang/fr_incl/langconfig.php
new file mode 100644
index 0000000000000..6474c8d415e72
--- /dev/null
+++ b/install/lang/fr_incl/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'fr';
+$string['thislanguage'] = 'Français (écriture inclusive)';
diff --git a/install/lang/fr_wp/langconfig.php b/install/lang/fr_wp/langconfig.php
new file mode 100644
index 0000000000000..7c85fcfcc90a6
--- /dev/null
+++ b/install/lang/fr_wp/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'fr';
+$string['thislanguage'] = 'Français pour Workplace';
diff --git a/install/lang/gl/error.php b/install/lang/gl/error.php
index 2c16045194914..3012c29edf8a7 100644
--- a/install/lang/gl/error.php
+++ b/install/lang/gl/error.php
@@ -34,17 +34,17 @@
A base de datos especificada non existe e o usuario indicado non ten permiso para crear a base de datos.
O administrador do sitio debería verificar a configuración da base de datos.
';
$string['cannotcreatelangdir'] = 'Non se pode crear o directorio de idioma';
-$string['cannotcreatetempdir'] = 'Non se pode crear un directorio temporal';
-$string['cannotdownloadcomponents'] = 'Non foi posíbel descargar compoñentes';
-$string['cannotdownloadzipfile'] = 'Non foi posíbel descargar o ficheiro ZIP';
-$string['cannotfindcomponent'] = 'Non foi posíbel atopar o compoñente';
+$string['cannotcreatetempdir'] = 'Non é posíbel crear un directorio temporal';
+$string['cannotdownloadcomponents'] = 'Non é posíbel descargar compoñentes';
+$string['cannotdownloadzipfile'] = 'Non é posíbel descargar o arquivo ZIP';
+$string['cannotfindcomponent'] = 'Non é posíbel atopar o compoñente';
$string['cannotsavemd5file'] = 'Non é posíbel gardar o ficheiro md5';
$string['cannotsavezipfile'] = 'Non é posíbel gardar o arquivo ZIP';
$string['cannotunzipfile'] = 'Non é posíbel descomprimir o ficheiro';
$string['componentisuptodate'] = 'O compoñente está actualizado';
$string['dmlexceptiononinstall'] = '
Produciuse un erro na base de datos [{$a->errorcode}].
{$a->debuginfo}
';
$string['downloadedfilecheckfailed'] = 'A comprobación do ficheiro descargado non foi satisfactoria';
-$string['invalidmd5'] = 'md5 non válido';
+$string['invalidmd5'] = 'A variábel de verificación non é correcta, ténteo de novo';
$string['missingrequiredfield'] = 'Falta algún campo obrigatorio';
$string['remotedownloaderror'] = '
Fallo a descarga do compoñente cara o seu servidor. Recomendase encarecidamente que verifiqoe os axustes do proxy, extensión PHP cURL.
Debe descargar o ficheiro {$a->url} manualmente, copialo en «{$a->dest}» no seu servidor e descomprimilo alí.
';
diff --git a/install/lang/gl/install.php b/install/lang/gl/install.php
index 117e7b691dd58..a4807e650152a 100644
--- a/install/lang/gl/install.php
+++ b/install/lang/gl/install.php
@@ -33,7 +33,7 @@
$string['admindirname'] = 'Directorio Admin';
$string['availablelangs'] = 'Lista de idiomas dispoñíbeis';
$string['chooselanguagehead'] = 'Escolla un idioma';
-$string['chooselanguagesub'] = 'Escolla un idioma para o proceso de instalación. Este idioma empregarase tamén como idioma predeterminado do sitio, se ben pode cambiarse máis adiante.';
+$string['chooselanguagesub'] = 'Escolla un idioma para o proceso de instalación. Este idioma empregarase tamén como idioma predeterminado do sitio, malia que pode cambiarse máis adiante.';
$string['clialreadyconfigured'] = 'Xa existe o ficheiro config.php. Empregue admin/cli/install_database.php se quere actualizar o seu sitio web.';
$string['clialreadyinstalled'] = 'Xa existe o ficheiro config.php. Empregue admin/cli/upgrade.php se quere actualizar o seu sitio web.';
$string['cliinstallheader'] = 'Programa de instalación de Moodle en liña de ordes {$a}';
@@ -46,7 +46,7 @@
$string['dirroot'] = 'Directorio de Moodle';
$string['environmenthead'] = 'Comprobando o seu entorno ...';
$string['environmentsub2'] = 'Cada versión de Moodle ten algún requisito mínimo da versión de PHP e un número obrigatorio de extensións de PHP.
-Antes de cada instalación ou actualización faise unha comprobación completa do entorno . Póñase en contacto co administrador do servidor se non sabe como instalar a nova versión ou activar as extensións PHP.';
+Antes de cada instalación ou actualización faise unha comprobación completa do entorno. Póñase en contacto co administrador do servidor se non sabe como instalar a nova versión ou activar as extensións PHP.';
$string['errorsinenvironment'] = 'A comprobación do entorno no foi satisfactoria!';
$string['installation'] = 'Instalación';
$string['langdownloaderror'] = 'Non foi posíbel descargar o idioma «{$a}». O proceso de instalación continuará en inglés.';
@@ -70,29 +70,29 @@
(poderá ver os erros cando se miran as páxinas) de modo que terá que eliminar o ficheiro .htaccess.
';
$string['paths'] = 'Rutas';
-$string['pathserrcreatedataroot'] = 'O directorio de datos ({$a->dataroot}) non puido ser creado polo instalador.';
+$string['pathserrcreatedataroot'] = 'O instalador non pode crear o directorio de datos ({$a->dataroot}).';
$string['pathshead'] = 'Confirme as rutas';
$string['pathsrodataroot'] = 'O directorio dataroot non ten permisos de escritura.';
$string['pathsroparentdataroot'] = 'O directorio principal ({$a->parent}) non ten permisos de escritura. O instalador non pode crear o directorio de datos ({$a->dataroot}).';
$string['pathssubadmindir'] = 'Moi poucos enderezos web empregan /admin como URL especial para
permitirlle acceder a un panel de control ou semellante. Desafortunadamente, isto entra en conflito coa localización estándar das páxinas de administración de Moodle. Vostede pode corrixir isto
renomeando o directorio admin na súa instalación, e poñendo aquí ese novo nome. Por exemplo:
moodleadmin. Iso corrixirá as ligazóns admin en Moodle.';
-$string['pathssubdataroot'] = 'Necesitase un lugar no que Moodle poida gardar os ficheiros enviados. Este directorio debe ser lexíbel E ESCRIBÍBEL polo usuario do servidor web
-(normalmente «nobody», «apache», «www-data»), mais non debería ser accesíbel directamente desde o web. Se non existe o instalador tentará crealo.';
+$string['pathssubdataroot'] = '
Un directorio onde Moodle almacenará todo o contido de ficheiros enviados polos usuarios.
+
Este directorio debería ser lexible e escribíbel polo usuario do servidor web (normalmente «www-data«» «ninguén» ou «apache»).
+
Non debe ser accesíbel directamente na web.
+
Se o directorio non existe actualmente, o proceso de instalación tentará crealo.
';
$string['pathssubdirroot'] = 'Ruta completa do directorio de instalación de Moodle.';
-$string['pathssubwwwroot'] = 'Enderezo web completo para acceder a Moodle.
-Non é posíbel acceder a Moodle empregando enderezos múltiples.
-Se o seu sitio ten varios enderezos públicos debe configurar encamiñamentos permanentes en todos eles, agás neste.
-Se o seu sitio web é accesíbel tanto desde unha Intranet como desde Internet, escriba aquí o enderezo público e configure o DNS para que os usuarios da Intranet poidan empregar tamén o enderezo público.
-Se o enderezo non é correcto, cambie o URL no seu navegador para reiniciar a instalación cun valor diferente.';
-$string['pathsunsecuredataroot'] = 'A localización de dataroot non é segura';
+$string['pathssubwwwroot'] = '
O enderezo completo onde se accederá a Moodle, é dicir, o enderezo que os usuarios introducirán na barra de enderezos do seu navegador para acceder a Moodle.
+
Non é posible acceder a Moodle con varias direccións. Se o seu sitio é accesible a través de varios enderezos, escolla o máis sinxelo e configure unha redirección permanente para cada un dos outros enderezos.
+
+
Se o enderezo actual non é correcto, cambie o URL na barra de enderezos do seu navegador e reinicie a instalación.
';
+$string['pathsunsecuredataroot'] = 'A localización de «dataroot» non é segura';
$string['pathswrongadmindir'] = 'Non existe o directorio Admin';
$string['phpextension'] = 'Extensión PHP {$a}';
$string['phpversion'] = 'Versión PHP';
-$string['phpversionhelp'] = '
Moodle require polo menos unha das versións de PHP 4.3.0 ou 5.1.0 ( as versións 5.0.x teñen unha serie de problemas coñecidos).
+$string['phpversionhelp'] = '
Moodle require polo menos unha das versións de PHP 5.6.5 ou 7.1 (7.0.x ten algunhas limitacións de motor).
Neste momento está executandose a versión {$a}
-
Debe actualizar PHP ou trasladarse a outro servidor cunha versión máis recente de PHP!
-(NO caso de 5.0.x podería tamén reverter cara a versión 4.4.x)
';
+
Debe actualizar PHP ou trasladarse a outro servidor cunha versión máis recente de PHP.
';
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['welcomep20'] = 'Se esta a ver esta páxina é porque puido instalar satisfactoriamente e
executar o paquete
{$a->packname} {$a->packversion} no seu computador. Parabéns!';
diff --git a/install/lang/he_kids/langconfig.php b/install/lang/he_kids/langconfig.php
index 361ecf260af74..5fd4b98bae4b1 100644
--- a/install/lang/he_kids/langconfig.php
+++ b/install/lang/he_kids/langconfig.php
@@ -31,4 +31,5 @@
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = 'he';
+$string['thisdirection'] = 'rtl';
$string['thislanguage'] = 'עברית בתי־ספר';
diff --git a/install/lang/he_wp/admin.php b/install/lang/he_wp/admin.php
new file mode 100644
index 0000000000000..bdaed906b5bca
--- /dev/null
+++ b/install/lang/he_wp/admin.php
@@ -0,0 +1,35 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['clianswerno'] = 'ל';
+$string['cliansweryes'] = 'כ';
+$string['cliincorrectvalueretry'] = 'ערך לא תקין, נסו שוב בבקשה';
diff --git a/install/lang/he_wp/langconfig.php b/install/lang/he_wp/langconfig.php
new file mode 100644
index 0000000000000..8bfbc7812fb06
--- /dev/null
+++ b/install/lang/he_wp/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'he';
+$string['thislanguage'] = 'עברית עבור Workplace';
diff --git a/install/lang/hi_wp/langconfig.php b/install/lang/hi_wp/langconfig.php
new file mode 100644
index 0000000000000..a8794458d8a06
--- /dev/null
+++ b/install/lang/hi_wp/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'hi';
+$string['thislanguage'] = 'वर्कप्लेस के लिए हिंदी';
diff --git a/install/lang/hr/admin.php b/install/lang/hr/admin.php
index bffba6d78ff2f..1177582bcf923 100644
--- a/install/lang/hr/admin.php
+++ b/install/lang/hr/admin.php
@@ -37,7 +37,7 @@
$string['clitypevalue'] = 'unesite vrijednost';
$string['clitypevaluedefault'] = 'unesite vrijednost ili pritisnite Enter za korištenje zadane vrijednosti ({$a})';
$string['cliunknowoption'] = 'Nepoznate opcije: {$a} Molimo koristite --help opciju.';
-$string['cliyesnoprompt'] = 'unesite y (znači da) ili n (znači ne)';
+$string['cliyesnoprompt'] = 'unesite d (znači da) ili n (znači ne)';
$string['environmentrequireinstall'] = 'je neophodno instalirati/omogućiti';
$string['environmentrequireversion'] = 'neophodna inačica je {$a->needed}, a vi trenutačno koristite inačicu {$a->current}';
$string['upgradekeyset'] = 'Ključ za ažuriranje (ostavite prazno kako ga ne bi zadali)';
diff --git a/install/lang/hr_schools/langconfig.php b/install/lang/hr_schools/langconfig.php
new file mode 100644
index 0000000000000..507610dc8fbf2
--- /dev/null
+++ b/install/lang/hr_schools/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'hr';
+$string['thislanguage'] = 'Croatian schools';
diff --git a/install/lang/hu/install.php b/install/lang/hu/install.php
index 964592c80508e..ea09537a87bd1 100644
--- a/install/lang/hu/install.php
+++ b/install/lang/hu/install.php
@@ -75,7 +75,7 @@
$string['welcomep20'] = 'Azért látja ezt az oldalt, mert sikeresen telepítette és futtatja az {$a->packname} {$a->packversion} csomagot számítógépén. Gratulálunk!';
$string['welcomep30'] = 'A {$a->installername} tartalmazza azokat az alkalmazásokat, amelyekkel a Moodle számára kialakítható a működési környezet, azaz:';
$string['welcomep40'] = 'A csomag tartalmazza a Moodle {$a->moodlerelease} ({$a->moodleversion})-t is.';
-$string['welcomep50'] = 'A csomagban lévő alkalmazások használatára a vonatkozó engedélyek érvényesek. A teljes {$a->installername} csomag
nyílt forráskódú, közreadása pedig a
GPL-licenc alapján történik.';
+$string['welcomep50'] = 'A csomagban lévő alkalmazások használatára a vonatkozó engedélyek érvényesek. A teljes {$a->installername} csomag
nyílt forráskódú, közreadása pedig a
GPL-licenc alapján történik.';
$string['welcomep60'] = 'A következő oldalak segítségével számítógépén egyszerűen telepítheti és beállíthatja a Moodle-t. Elfogadhatja az alapbeállításokat, de igényeinek megfelelően módosíthatja is őket.';
$string['welcomep70'] = 'Kattintson az alábbi "Következő" gombra és folytassa a Moodle telepítését.';
$string['wwwroot'] = 'Webcím';
diff --git a/install/lang/id/install.php b/install/lang/id/install.php
index 691d6d4c01713..8ce4af32c92f3 100644
--- a/install/lang/id/install.php
+++ b/install/lang/id/install.php
@@ -33,15 +33,31 @@
$string['admindirname'] = 'Direktori admin';
$string['availablelangs'] = 'Paket bahasa yang tersedia';
$string['chooselanguagehead'] = 'Pilih bahasa';
-$string['chooselanguagesub'] = 'Silakan pilih bahasa untuk instalasi. Bahasa ini juga akan digunakan sebagai bahasa default untuk situs, meskipun mungkin akan diubah kemudian.';
-$string['clialreadyconfigured'] = 'Berkas konfigurasi config.php sudah ada. Silakan gunakan admin /cli/install_database.php untuk menginstal Moodle untuk situs ini.';
-$string['clialreadyinstalled'] = 'File konfigurasi config.php sudah ada. Silakan gunakan admin/cli/install_database.php untuk menginstal Moodle untuk situs ini.';
-$string['databasehost'] = 'Host basis data';
+$string['chooselanguagesub'] = 'Sila pilih bahasa untuk instalasi. Bahasa ini juga akan digunakan sebagai bahasa bawaan untuk situs, meskipun mungkin akan diubah kemudian.';
+$string['clialreadyconfigured'] = 'Berkas konfigurasi config.php sudah ada. Sila gunakan admin /cli/install_database.php untuk memasang Moodle untuk situs ini.';
+$string['clialreadyinstalled'] = 'Berkas konfigurasi config.php sudah ada. Silakan gunakan admin/cli/install_database.php untuk menginstal Moodle untuk situs ini.';
+$string['cliinstallheader'] = 'Program pemasangan baris perintah Moodle {$a}';
+$string['databasehost'] = 'Hos basis data';
$string['databasename'] = 'Nama basis data';
$string['databasetypehead'] = 'Pilih pengandar basis data';
$string['dataroot'] = 'Direktori data';
+$string['datarootpermission'] = 'Izin direktori data';
$string['dbprefix'] = 'Prefiks tabel';
+$string['dirroot'] = 'Direktori Moodle';
+$string['environmenthead'] = 'Memeriksa sistem Anda ...';
+$string['environmentsub2'] = 'Setiap rilis Moodle memiliki beberapa persyaratan versi PHP minimum dan sejumlah ekstensi PHP wajib. Pemeriksaan komponen sistem akan dilakukan sebelum pemasangan dan peningkatan versi. Silakan hubungi administrator peladen jika Anda tidak tahu cara mamasang versi baru atau mengaktifkan ekstensi PHP.';
+$string['errorsinenvironment'] = 'Pemeriksaan sistem gagal!';
$string['installation'] = 'Instalasi';
+$string['langdownloaderror'] = 'Sayangnya bahasa "{$a}" tidak dapat diunduh. Proses instalasi akan dilanjutkan dalam bahasa Inggris.';
+$string['memorylimithelp'] = '
Batas memori PHP untuk server Anda saat ini diatur ke {$a}.
Ini dapat menyebabkan Moodle memiliki masalah memori di kemudian hari, terutama jika Anda memiliki banyak modul yang diaktifkan dan/atau banyak pengguna.
Kami menyarankan Anda mengkonfigurasi PHP dengan batas yang lebih tinggi jika memungkinkan, seperti 40M. Ada beberapa cara untuk melakukan ini yang dapat Anda coba:
+
- Jika Anda bisa, kompilasi ulang PHP dengan --enable-memory-limit . Ini memungkinkan Moodle untuk mengatur batas memori itu sendiri.
+ - Jika Anda memiliki akses ke file php.ini, Anda dapat mengubah pengaturan memory_limit di sana menjadi sekitar 40M. Jika Anda tidak memiliki akses, Anda mungkin dapat meminta administrator untuk melakukan ini untuk Anda.
+- Pada beberapa server PHP, Anda dapat membuat file .htaccess di direktori Moodle yang berisi baris ini:
php_value memory_limit 40M
Namun, pada beberapa server ini tidak diizinkan semua halaman PHP tidak berfungsi (Anda akan melihat kesalahan ketika Anda melihat halaman) sehingga Anda Anda harus menghapus file .htaccess.
';
+$string['paths'] = 'Jalur';
+$string['pathserrcreatedataroot'] = 'Direktori data ({$a->dataroot}) tidak dapat dibuat oleh installer.';
+$string['pathshead'] = 'Konfirmasi jalur';
+$string['pathsrodataroot'] = 'Direktori data root tidak dapat ditulisi.';
+$string['pathsroparentdataroot'] = 'Direktori induk ({$a->parent}) tidak dapat ditulisi. Direktori data ({$a->dataroot}) tidak dapat dibuat oleh installer.';
$string['pathssubadmindir'] = 'Beberapa hosting menggunakan / admin sebagai URL khusus untuk Anda mengakses panel kontrol atau sesuatu. Sayangnya ini bertentangan dengan lokasi standar untuk halaman admin Moodle. Anda dapat memperbaikinya dengan mengganti nama direktori admin di instalasi Anda, dan meletakkan nama baru itu di sini. Misalnya:
moodleadmin . Ini akan memperbaiki tautan admin di Moodle.';
$string['pathssubdataroot'] = '
Direktori tempat Moodle akan menyimpan semua konten file yang diunggah oleh pengguna.
Direktori ini harus dapat dibaca dan ditulis oleh pengguna server web (biasanya \'www-data\', \'nobody\', atau \' apache \').
Itu tidak boleh diakses secara langsung melalui web.
Jika direktori saat ini tidak ada, proses instalasi akan berusaha membuatnya.
';
$string['pathssubdirroot'] = '
Jalur lengkap ke direktori yang berisi kode Moodle.
';
@@ -56,6 +72,6 @@
$string['welcomep30'] = 'Rilis
{$a->installername} ini mencakup aplikasi untuk menciptakan lingkungan tempat
Moodle yang akan digunakan, yaitu:';
$string['welcomep40'] = 'Paket juga termasuk
Moodle {$a->moodlerelease} ({$a->moodleversion}).';
$string['welcomep50'] = 'Penggunaan semua aplikasi dalam paket ini diatur oleh lisensi masing-masing. Paket
{$a->installername} lengkap adalah
sumber terbuka dan didistribusikan di bawah lisensi
GPL .';
-$string['welcomep60'] = 'Halaman-halaman berikut akan menuntun Anda melalui beberapa langkah yang mudah diikuti untuk mengonfigurasi dan menyiapkan
Moodle di komputer Anda. Anda dapat menerima pengaturan bawaan atau, secara opsional, mengubahnya sesuai dengan kebutuhan Anda.';
-$string['welcomep70'] = 'Klik tombol "Selanjutnya" di bawah untuk melanjutkan dengan penyiapan
Moodle .';
+$string['welcomep60'] = 'Halaman berikut akan menuntun Anda melalui beberapa langkah yang mudah diikuti untuk mengonfigurasi dan menyiapkan
Moodle di komputer Anda. Anda dapat menerima pengaturan bawaan atau, secara opsional, mengubahnya sesuai dengan kebutuhan Anda.';
+$string['welcomep70'] = 'Klik tombol "Selanjutnya" di bawah untuk melanjutkan instalasi
Moodle .';
$string['wwwroot'] = 'Alamat web';
diff --git a/install/lang/ja/install.php b/install/lang/ja/install.php
index a53560434a703..fb4dcf94a6eb5 100644
--- a/install/lang/ja/install.php
+++ b/install/lang/ja/install.php
@@ -57,7 +57,7 @@
- あなたがリコンパイル可能な場合、PHPを--enable-memory-limitオプションでコンパイルしてください。これにより、Moodle自身がメモリ制限を設定することが可能になります。
- あなたがphp.iniファイルにアクセスできる場合、memory_limit設定を40Mのように変更することができます。php.iniファイルにアクセスできない場合、管理者に変更を依頼してください。
-- いくつかのPHPサーバでは下記の行を含む.htaccessファイルをMoodleディレクトリに作成することができます:
+
- いくつかのPHPサーバでは以下の行を含む.htaccessファイルをMoodleディレクトリに作成することができます:
php_value memory_limit 40M
しかし、この設定がすべてのPHPページの動作を妨げる場合もあります。ページ閲覧中にエラーが表示される場合、.htaccessファイルを削除してください。
';
@@ -91,7 +91,7 @@
$string['welcomep20'] = 'インストールが正常に完了して、あなたのコンピュータで
{$a->packname} {$a->packversion} パッケージが起動されたため、このページが表示されています。おめでとうございます!';
$string['welcomep30'] = 'このリリース
{$a->installername} には
Moodleで環境を作成するアプリケーションが含まれています。すなわち:';
$string['welcomep40'] = 'パッケージには
Moodle {$a->moodlerelease} ({$a->moodleversion}) も含まれています。';
-$string['welcomep50'] = 'このパッケージ内のすべてのアプリケーションの使用は個別のライセンスによって規定されています。全体の
{$a->installername}パッケージは
オープンソースであり、
GPLライセンスの下で配布されています。';
+$string['welcomep50'] = 'このパッケージ内のすべてのアプリケーションの使用は個別のライセンスによって規定されています。全体の
{$a->installername}パッケージは
オープンソースであり、
GPLライセンスの下で配布されています。';
$string['welcomep60'] = '次からのページはあなたのコンピュータに
Moodleを簡単に設定およびセットアップする手順にしたがって進みます。あなたはデフォルトの設定を使用することも、必要に応じて任意で設定を変更することもできます。';
$string['welcomep70'] = '
Moodleのセットアップを続けるには「次へ」ボタンをクリックしてください。';
$string['wwwroot'] = 'ウェブアドレス';
diff --git a/install/lang/ka/install.php b/install/lang/ka/install.php
index 3ffbdac6f17d0..bb8a68b84efd8 100644
--- a/install/lang/ka/install.php
+++ b/install/lang/ka/install.php
@@ -32,6 +32,7 @@
$string['admindirname'] = 'ადმინისტრატორის დირექტორია';
$string['availablelangs'] = 'ხელმისაწვდომი ენის პაკეტები';
+$string['chooselanguagehead'] = 'აირჩიეთ ენა';
$string['dataroot'] = 'მონაცემტა დირექტორია';
$string['dbprefix'] = 'ცხრილების პრეფიქსი';
$string['dirroot'] = 'Moodle-ის დირექტორია';
diff --git a/install/lang/km/admin.php b/install/lang/km/admin.php
index 6b5b2408481a1..71c6d8f6ebb66 100644
--- a/install/lang/km/admin.php
+++ b/install/lang/km/admin.php
@@ -30,5 +30,6 @@
defined('MOODLE_INTERNAL') || die();
+$string['clianswerno'] = 'ទេ';
$string['environmentrequireinstall'] = 'ត្រូវតែបានដំឡើង និងអនុញ្ញាត';
$string['environmentrequireversion'] = 'ត្រូវការកំណែ {$a->needed} ហើយអ្នកកំពុងរត់ {$a->current}';
diff --git a/install/lang/km/error.php b/install/lang/km/error.php
index 114fcfe083e2c..c39229547588d 100644
--- a/install/lang/km/error.php
+++ b/install/lang/km/error.php
@@ -41,7 +41,7 @@
$string['componentisuptodate'] = 'សមាសភាគគឺទាន់សម័យ ។';
$string['downloadedfilecheckfailed'] = 'បានបរាជ័យក្នុងការពិនិត្យឯកសារដែលបានទាញយក ។';
$string['invalidmd5'] = 'md5 មិនត្រឹមត្រូវ';
-$string['missingrequiredfield'] = 'បាត់វាលដែលត្រូវការមួយចំនួន';
+$string['missingrequiredfield'] = 'បាត់ប្រអប់ទិន្នន័យដែលត្រូវទាមទារមួយចំនួន';
$string['remotedownloaderror'] = 'បរាជ័យក្នុងការទាញយកសមាសភាគទៅម៉ាស៊ីនបម្រើរបស់អ្នក សូមផ្ទៀងផ្ទាត់ប្រូកស៊ី ផ្នែកបន្ថែម PHP cURL ត្រូវបានផ្ដល់អនុសាសន៍ ។
អ្នកត្រូវតែទាញយកឯកសារ
{$a->url} ដោយដៃ ចម្លងវាទៅ "{$a->dest}" ក្នុងម៉ាស៊ីនបម្រើរបស់អ្នក និងពន្លាវានៅទីនោះ ។';
$string['wrongdestpath'] = 'ផ្លូវទិសដៅមិនត្រឹមត្រូវ ។';
$string['wrongsourcebase'] = 'មូលដ្ឋាន URL ប្រភពមិនត្រឹមត្រូវ ។';
diff --git a/install/lang/my/langconfig.php b/install/lang/my/langconfig.php
index 768a9c95cb5b7..af3818c8cd78e 100644
--- a/install/lang/my/langconfig.php
+++ b/install/lang/my/langconfig.php
@@ -30,4 +30,4 @@
defined('MOODLE_INTERNAL') || die();
-$string['thislanguage'] = 'myanma bhasa';
+$string['thislanguage'] = 'ဗမာစာ';
diff --git a/install/lang/nl/install.php b/install/lang/nl/install.php
index 623e935c200e2..27bc4115ff228 100644
--- a/install/lang/nl/install.php
+++ b/install/lang/nl/install.php
@@ -88,7 +88,7 @@
$string['welcomep30'] = 'Deze uitgave van
{$a->installername} bevat de software die nodig is om een omgeving te creëren waarin
Moodle zal werken, namelijk:';
$string['welcomep40'] = 'Dit pakket bevat ook
Moodle {$a->moodlerelease} ({$a->moodleversion}).';
$string['welcomep50'] = 'Het gebruik van alle programma\'s in dit pakket wordt geregeld door hun respectievelijke licenties. Het complete
{$a->installername} pakket is
-
open source en wordt verdeeld onder de
GPL licentie.';
+
open source en wordt verdeeld onder de
GPL licentie.';
$string['welcomep60'] = 'De volgende pagina\'s leiden je door een aantal makkelijk te volgen stappen om
Moodle te installeren op je computer. Je kunt de standaardinstellingen overnemen of, optioneel, ze aanpassen aan je noden.';
$string['welcomep70'] = 'Klik op de "volgende"-knop om verder te gaan met de installatie van
Moodle';
$string['wwwroot'] = 'Web adres';
diff --git a/course/publish/lib.php b/install/lang/om/langconfig.php
similarity index 57%
rename from course/publish/lib.php
rename to install/lang/om/langconfig.php
index 72330f6fe23ad..58f2c8d7466fe 100644
--- a/course/publish/lib.php
+++ b/install/lang/om/langconfig.php
@@ -1,4 +1,5 @@
.
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'Afaan Oromoo';
diff --git a/install/lang/pl/admin.php b/install/lang/pl/admin.php
index c87bb8691a6d4..9815b4ea171c9 100644
--- a/install/lang/pl/admin.php
+++ b/install/lang/pl/admin.php
@@ -40,6 +40,6 @@
{$a}
Proszę użyć pomocy.';
$string['cliyesnoprompt'] = 'wpisz y (czyli tak) lub n (czyli nie)';
-$string['environmentrequireinstall'] = 'jest niezbędnę, żeby było zainstalowane/włączone';
+$string['environmentrequireinstall'] = 'jest niezbędne, aby było zainstalowane i włączone';
$string['environmentrequireversion'] = 'wersja {$a->needed} jest niezbędna a ty używasz wersji {$a->current}';
$string['upgradekeyset'] = 'Zaktualizuj klucz (pozostaw puste jeśli nie jest to skonfigurowane)';
diff --git a/install/lang/pt/install.php b/install/lang/pt/install.php
index 4ff411011fe4e..61f701b9fa888 100644
--- a/install/lang/pt/install.php
+++ b/install/lang/pt/install.php
@@ -61,7 +61,7 @@
Não deve ser diretamente acessível através da web.
Se a diretoria não existir atualmente, o processo de instalação tentará criá-la.
';
$string['pathssubdirroot'] = 'Caminho completo para a diretoria que contém o código Moodle.';
-$string['pathssubwwwroot'] = 'Endereço web completo de acesso ao Moodle. Não é possível aceder ao Moodle usando mais do que um endereço. Se o site tiver mais do que um endereço público, devem ser configurados redirecionamentos permanentes em todos eles, à exceção deste. Se o site pode ser acedido a partir da Internet e de Intranet, então use o endereço público aqui. Se o endereço atual não está correto, altere o endereço indicado na barra de endereço do seu navegador e reinicie a instalação.';
+$string['pathssubwwwroot'] = 'Endereço web completo de acesso ao Moodle. Não é possível aceder ao Moodle usando mais do que um endereço. Se o site tiver mais do que um endereço público, devem ser configurados redirecionamentos permanentes em todos eles, à exceção deste. Se o site pode ser acedido a partir da Internet e de Intranet, use o endereço público aqui. Se o endereço atual não está correto, altere o endereço indicado na barra de endereço do seu navegador e reinicie a instalação.';
$string['pathsunsecuredataroot'] = 'A localização da pasta de dados não é segura';
$string['pathswrongadmindir'] = 'A pasta
admin não existe';
$string['phpextension'] = 'Extensão
{$a} do PHP';
@@ -72,8 +72,8 @@
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['welcomep20'] = 'A apresentação desta página confirma a correta instalação e ativação do pacote
{$a->packname} {$a->packversion} no servidor.';
$string['welcomep30'] = 'Esta versão do pacote
{$a->installername} inclui as aplicações necessárias para o correto funcionamento do
Moodle, nomeadamente:';
-$string['welcomep40'] = 'Este pacote inclui
Moodle {$a->moodlerelease} ({$a->moodleversion}).';
-$string['welcomep50'] = 'A utilização de todas as aplicações incluídas neste pacote é limitada pelas respetivas licenças. O pacote completo
{$a->installername} é
código aberto e distribuído nos termos da licença GPL.';
+$string['welcomep40'] = 'Este pacote inclui o lançamento {$a->moodlerelease} do Moodle ({$a->moodleversion}).';
+$string['welcomep50'] = 'A utilização de todas as aplicações incluídas neste pacote é limitada pelas respetivas licenças. O pacote completo {$a->installername} é código aberto e é distribuído nos termos da licença GPL.';
$string['welcomep60'] = 'As páginas seguintes irão levá-lo através de alguns passos simples para
configurar e definir o Moodle no seu computador. Você pode aceitar as configurações predefinidas ou, opcionalmente, alterá-las para atender às suas próprias necessidades.';
$string['welcomep70'] = 'Clique no botão "Seguinte" para continuar a configuração do Moodle.';
diff --git a/install/lang/ro_wp/admin.php b/install/lang/ro_wp/admin.php
new file mode 100644
index 0000000000000..f6d63293545a7
--- /dev/null
+++ b/install/lang/ro_wp/admin.php
@@ -0,0 +1,37 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['clianswerno'] = 'n';
+$string['cliansweryes'] = 'y';
+$string['cliincorrectvalueretry'] = 'Valoarea nu este corectă, încercați din nou';
+$string['environmentrequireinstall'] = 'trebuie să fie instalat și activat';
+$string['environmentrequireversion'] = 'versiunea {$a->needed} este necesară iar dumneavoastră rulați {$a->current}';
diff --git a/install/lang/ro_wp/langconfig.php b/install/lang/ro_wp/langconfig.php
new file mode 100644
index 0000000000000..0842224b79ef9
--- /dev/null
+++ b/install/lang/ro_wp/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'ro';
+$string['thislanguage'] = 'Workplace în limba română';
diff --git a/install/lang/ro_wp/moodle.php b/install/lang/ro_wp/moodle.php
new file mode 100644
index 0000000000000..8a40f61ddc0a6
--- /dev/null
+++ b/install/lang/ro_wp/moodle.php
@@ -0,0 +1,37 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['language'] = 'Limbă';
+$string['moodlelogo'] = 'Logo Moodle';
+$string['next'] = 'Următoarea';
+$string['previous'] = 'Anterior';
+$string['reload'] = 'Reîncarcă';
diff --git a/install/lang/rw/langconfig.php b/install/lang/rw/langconfig.php
new file mode 100644
index 0000000000000..a214772b2275f
--- /dev/null
+++ b/install/lang/rw/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thisdirection'] = 'ltr';
+$string['thislanguage'] = 'Kinyarwanda';
diff --git a/install/lang/se/install.php b/install/lang/se/install.php
new file mode 100644
index 0000000000000..4c072b2db77e3
--- /dev/null
+++ b/install/lang/se/install.php
@@ -0,0 +1,39 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['availablelangs'] = 'Giellapáhkat mat leat gávdnamis';
+$string['chooselanguagehead'] = 'Vállje giela';
+$string['chooselanguagesub'] = 'Vállje giela (dušše installašuvdnjii). Don sáhtát válljet neahttabáikki ja geavaheaddji giela šearbmagovas maŋŋelaš.';
+$string['clialreadyconfigured'] = 'Fiila config.php gávdno jo. Geavat admin/cli/install_database.php jus áiggut installeret dán portála.';
+$string['clialreadyinstalled'] = 'Fiila config.php gávdno jo. Geavat admin/cli/install_database.php jus háliidat ođasmahttit Moodle dán portálas.';
+$string['langdownloaderror'] = 'Dađibahábut ii installerejuvvon giellapáhkka "{$a}". Installašuvdnaproseassa joatká eaŋgalsgillii.';
+$string['phpextension'] = '{$a} PHP gilkor';
diff --git a/install/lang/se/moodle.php b/install/lang/se/moodle.php
new file mode 100644
index 0000000000000..7fd6b2d4af20c
--- /dev/null
+++ b/install/lang/se/moodle.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['language'] = 'Giella';
+$string['next'] = 'Boahtte';
diff --git a/install/lang/sl/langconfig.php b/install/lang/sl/langconfig.php
index 7a7b99f061c95..9e0be7b06cc70 100644
--- a/install/lang/sl/langconfig.php
+++ b/install/lang/sl/langconfig.php
@@ -30,5 +30,6 @@
defined('MOODLE_INTERNAL') || die();
+$string['parentlanguage'] = '';
$string['thisdirection'] = 'ltr';
-$string['thislanguage'] = 'Slovenščina';
+$string['thislanguage'] = 'Slovenščina';
diff --git a/install/lang/sr_cr/install.php b/install/lang/sr_cr/install.php
index 6ee89b7fa237b..c98d2ece9439c 100644
--- a/install/lang/sr_cr/install.php
+++ b/install/lang/sr_cr/install.php
@@ -87,7 +87,7 @@
$string['welcomep20'] = 'Ову страницу видите зато што сте успешно инсталирали и покренули {$a->packname} {$a->packversion} пакет на свом серверу. Честитамо!';
$string['welcomep30'] = 'Ово издање {$a->installername} укључује апликације за креирање окружења у којем ће Moodle успешно функционисати, конкретно:';
$string['welcomep40'] = 'Овај пакет обухвата и Moodle {$a->moodlerelease} ({$a->moodleversion}).';
-$string['welcomep50'] = 'Коришћење свих апликација овог пакета је уређено њиховим лиценцама. Комплетан{$a->installername} пакет је отвореног кода и дистрибуира се под GPL лиценцом.';
+$string['welcomep50'] = 'Коришћење свих апликација овог пакета је уређено њиховим лиценцама. Комплетан{$a->installername} пакет је отвореног кода и дистрибуира се под GPL лиценцом.';
$string['welcomep60'] = 'Наредне странице ће вас провести кроз неколико једноставних корака током којих ћете конфигурисати и подесити Moodle на свом рачунару. Можете прихватити подразумевана подешавања или их, опционо, прилагодити сопственим потребама.';
$string['welcomep70'] = 'Кликните на дугме за наставак да бисте даље подешавали Moodle.';
$string['wwwroot'] = 'Веб адреса';
diff --git a/install/lang/sr_lt/install.php b/install/lang/sr_lt/install.php
index c9a03ee5a7ed1..adb8e4ed2a4ef 100644
--- a/install/lang/sr_lt/install.php
+++ b/install/lang/sr_lt/install.php
@@ -84,7 +84,7 @@
$string['welcomep20'] = 'Ovu stranicu vidite zato što ste uspešno instalirali i pokrenuli {$a->packname} {$a->packversion} paket na svom serveru. Čestitamo!';
$string['welcomep30'] = 'Ovo izdanje {$a->installername} uključuje aplikacije za kreiranje okruženja u kojem će Moodle uspešno funkcionisati, konkretno:';
$string['welcomep40'] = 'Ovaj paket obuhvata i Moodle {$a->moodlerelease} ({$a->moodleversion}).';
-$string['welcomep50'] = 'Korišćenje svih aplikacija ovog paketa je uređeno njihovim licencama. Kompletan{$a->installername} paket je otvorenog koda i distribuira se pod GPL licencom.';
+$string['welcomep50'] = 'Korišćenje svih aplikacija ovog paketa je uređeno njihovim licencama. Kompletan{$a->installername} paket je otvorenog koda i distribuira se pod GPL licencom.';
$string['welcomep60'] = 'Naredne stranice će vas provesti kroz nekoliko jednostavnih koraka tokom kojih ćete konfigurisati i podesiti Moodle na svom računaru. Možete prihvatiti podrazumevana podešavanja ili ih, opciono, prilagoditi sopstvenim potrebama.';
$string['welcomep70'] = 'Kliknite na dugme za nastavak da biste dalje podešavali Moodle.';
$string['wwwroot'] = 'Web adresa';
diff --git a/install/lang/ta_lk/moodle.php b/install/lang/ta_lk/moodle.php
index de7a1f08e6068..21bd28a4b07aa 100644
--- a/install/lang/ta_lk/moodle.php
+++ b/install/lang/ta_lk/moodle.php
@@ -31,6 +31,7 @@
defined('MOODLE_INTERNAL') || die();
$string['language'] = 'மொழி';
+$string['moodlelogo'] = 'Moodle சின்னம்';
$string['next'] = 'அடுத்தது';
$string['previous'] = 'முன்னைய';
$string['reload'] = 'மீள ஏற்றுக';
diff --git a/install/lang/tpi/langconfig.php b/install/lang/tpi/langconfig.php
new file mode 100644
index 0000000000000..d97f94c2df73a
--- /dev/null
+++ b/install/lang/tpi/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thisdirection'] = 'ltr';
+$string['thislanguage'] = 'Tok Pisin';
diff --git a/install/lang/zh_cn_wp/langconfig.php b/install/lang/zh_cn_wp/langconfig.php
new file mode 100644
index 0000000000000..1b91c7624e4d2
--- /dev/null
+++ b/install/lang/zh_cn_wp/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'zh_cn';
+$string['thislanguage'] = 'Workplace 简体中文版';
diff --git a/install/lang/zh_tw_wp/langconfig.php b/install/lang/zh_tw_wp/langconfig.php
new file mode 100644
index 0000000000000..a00ce56d42125
--- /dev/null
+++ b/install/lang/zh_tw_wp/langconfig.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'zh_tw';
+$string['thislanguage'] = 'Workplace 繁體中文版';
diff --git a/iplookup/tests/fixtures/GeoIP2-City-Test.mmdb b/iplookup/tests/fixtures/GeoIP2-City-Test.mmdb
new file mode 100644
index 0000000000000..c304794f62ff1
Binary files /dev/null and b/iplookup/tests/fixtures/GeoIP2-City-Test.mmdb differ
diff --git a/iplookup/tests/fixtures/README.txt b/iplookup/tests/fixtures/README.txt
new file mode 100644
index 0000000000000..f12faa2ac0022
--- /dev/null
+++ b/iplookup/tests/fixtures/README.txt
@@ -0,0 +1,10 @@
+GeoIP2-City-Test.mmdb:
+ Copyright: maxmind (github.com/maxmind)
+
+ https://github.com/maxmind/MaxMind-DB/blob/master/test-data/GeoIP2-City-Test.mmdb
+
+ Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License
+
+ http://creativecommons.org/licenses/by-sa/3.0/
+
+ No changes have been made to this file.
diff --git a/iplookup/tests/geoip_test.php b/iplookup/tests/geoip_test.php
index b65be59962198..d553bd8938ab6 100644
--- a/iplookup/tests/geoip_test.php
+++ b/iplookup/tests/geoip_test.php
@@ -36,56 +36,15 @@
*/
class core_iplookup_geoip_testcase extends advanced_testcase {
public function setUp() {
- if (!PHPUNIT_LONGTEST) {
- // These tests are intensive and required downloads.
- $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
- }
-
$this->resetAfterTest();
}
-
/**
* Setup the GeoIP2File system.
*/
public function setup_geoip2file() {
global $CFG;
-
- // Store the file somewhere where it won't be wiped out..
- $gzfile = "$CFG->dataroot/phpunit/geoip/GeoLite2-City.mmdb.gz";
- check_dir_exists(dirname($gzfile));
- if (file_exists($gzfile) and (filemtime($gzfile) < time() - 60*60*24*30)) {
- // Delete file if older than 1 month.
- unlink($gzfile);
- }
-
- if (!file_exists($gzfile)) {
- download_file_content('http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz',
- null, null, false, 300, 20, false, $gzfile);
- }
-
- $this->assertTrue(file_exists($gzfile));
-
- $geoipfile = str_replace('.gz', '', $gzfile);
-
- // Open our files (in binary mode).
- $file = gzopen($gzfile, 'rb');
- $geoipfilebuf = fopen($geoipfile, 'wb');
-
- // Keep repeating until the end of the input file.
- while (!gzeof($file)) {
- // Read buffer-size bytes.
- // Both fwrite and gzread and binary-safe.
- fwrite($geoipfilebuf, gzread($file, 4096));
- }
-
- // Files are done, close files.
- fclose($geoipfilebuf);
- gzclose($file);
-
- $this->assertTrue(file_exists($geoipfile));
-
- $CFG->geoip2file = $geoipfile;
+ $CFG->geoip2file = "$CFG->dirroot/iplookup/tests/fixtures/GeoIP2-City-Test.mmdb";
}
/**
@@ -121,9 +80,8 @@ public function test_ip($ip) {
*/
public function ip_provider() {
return [
- 'IPv4: Sample suggested by maxmind themselves' => ['24.24.24.24'],
- 'IPv4: github.com' => ['192.30.255.112'],
- 'IPv6: UCLA' => ['2607:f010:3fe:fff1::ff:fe00:25'],
+ 'IPv4: IPV4 test' => ['81.2.69.142'],
+ 'IPv6: IPV6 test' => ['2001:252:1::1:1:1'],
];
}
}
diff --git a/lang/en/access.php b/lang/en/access.php
index 6fe361641fe0c..ae8e241fb74a7 100644
--- a/lang/en/access.php
+++ b/lang/en/access.php
@@ -29,6 +29,8 @@
$string['activitynext'] = 'Next activity';
$string['activityprev'] = 'Previous activity';
$string['breadcrumb'] = 'Navigation bar';
+$string['eventcontextlocked'] = 'Context frozen';
+$string['eventcontextunlocked'] = 'Context unfrozen';
$string['hideblocka'] = 'Hide {$a} block';
$string['showblocka'] = 'Show {$a} block';
$string['sitemap'] = 'Site map';
diff --git a/lang/en/admin.php b/lang/en/admin.php
index 26c89616de33b..f360e4f815406 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -112,8 +112,8 @@
$string['cannotdeletemodfilter'] = 'You cannot uninstall the \'{$a->filter}\' because it is part of the \'{$a->module}\' module.';
$string['cannotuninstall'] = '{$a} can not be uninstalled.';
$string['categoryemail'] = 'Email';
-$string['cfgwwwrootslashwarning'] = 'You have defined $CFG->wwwroot incorrectly in your config.php file. You have included a \'/\' character at the end. Please remove it, or you will experience strange bugs like MDL-11061.';
-$string['cfgwwwrootwarning'] = 'You have defined $CFG->wwwroot incorrectly in your config.php file. It does not match the URL you are using to access this page. Please correct it, or you will experience strange bugs like MDL-11061.';
+$string['cfgwwwrootslashwarning'] = '$CFG->wwwroot is defined incorrectly in the config.php file. It includes a \'/\' character at the end which must be removed.';
+$string['cfgwwwrootwarning'] = '$CFG->wwwroot is defined incorrectly in the config.php file. It should match the URL you are using to access this page.';
$string['cleanup'] = 'Cleanup';
$string['clianswerno'] = 'n';
$string['cliansweryes'] = 'y';
@@ -181,28 +181,26 @@
$string['configcoursesperpage'] = 'Enter the number of courses to be displayed per page in a course listing.';
$string['configcourseswithsummarieslimit'] = 'The maximum number of courses to display in a course listing including summaries before falling back to a simpler listing.';
$string['configcronclionly'] = 'Running the cron from a web browser can expose privileged information to anonymous users. Thus it is recommended to only run the cron from the command line or set a cron password for remote access.';
-$string['configcronremotepassword'] = 'This means that the cron.php script cannot be run from a web browser without supplying the password using the following form of URL:
- http://site.example.com/admin/cron.php?password=opensesame
-
If this is left empty, no password is required.';
+$string['configcronremotepassword'] = 'This means that the cron.php script cannot be run from a web browser without supplying the password using the following form of URL: https://site.example.com/admin/cron.php?password=opensesame
If this is left empty, no password is required.';
$string['configcurlcache'] = 'Time-to-live for cURL cache, in seconds.';
$string['configcustommenuitems'] = 'You can configure a custom menu here to be shown by themes. Each line consists of some menu text, a link URL (optional), a tooltip title (optional) and a language code or comma-separated list of codes (optional, for displaying the line to users of the specified language only), separated by pipe characters. Lines starting with a hyphen will appear as menu items in the previous top level menu, and dividers can be used by adding a line of one or more # characters where desired. For example:
Moodle community|https://moodle.org
-Moodle free support|https://moodle.org/support
--Moodle Docs|http://docs.moodle.org|Moodle Docs
--German Moodle Docs|http://docs.moodle.org/de|Documentation in German|de
+-Moodle Docs|https://docs.moodle.org|Moodle Docs
+-German Moodle Docs|https://docs.moodle.org/de|Documentation in German|de
-###
-Moodle development|https://moodle.org/development
-Moodle.com|http://moodle.com/
+Moodle.com|https://moodle.com/
';
$string['configcustomusermenuitems'] = 'You can configure the contents of the user menu (with the exception of the log out link, which is automatically added). Each line is separated by pipe characters and consists of 1) a string in "langstringname, componentname" form or as plain text, 2) a URL, and 3) an icon either as a pix icon (in the folder pix with the structure [subfoldername]/[iconname], e.g. i/publish) or as a URL. Dividers can be used by adding a line of one or more # characters where desired.';
$string['configdbsessions'] = 'If enabled, this setting will use the database to store information about current sessions. Note that changing this setting now will log out all current users (including you). If you are using MySQL please make sure that \'max_allowed_packet\' in my.cnf (or my.ini) is at least 4M. Other session drivers can be configured directly in config.php, see config-dist.php for more information. This option disappears if you specify session driver in config.php file.';
$string['configdebug'] = 'If you turn this on, then PHP\'s error_reporting will be increased so that more warnings are printed. This is only useful for developers.';
$string['configdebugdisplay'] = 'Set to on, the error reporting will go to the HTML page. This is practical, but breaks XHTML, JS, cookies and HTTP headers in general. Set to off, it will send the output to your server logs, allowing better debugging. The PHP setting error_log controls which log this goes to.';
$string['configdebugpageinfo'] = 'Enable if you want page information printed in page footer.';
-$string['configdebugsmtp'] = 'Enable verbose debug information during sending of email messages to SMTP server.';
+$string['configdebugsmtp'] = 'Enable verbose debug information during sending of email messages to SMTP server. For this setting to take effect, the \'Debug messages\' setting must be set to \'Developer\'.';
$string['configdebugvalidators'] = 'Enable if you want to have links to external validator servers in page footer. You may need to create new user with username w3cvalidator, and enable guest access. These changes may allow unauthorized access to server, do not enable on production sites!';
-$string['configdefaulthomepage'] = 'This determines the home page for logged in users';
+$string['configdefaulthomepage'] = 'This determines the first link in the navigation for logged-in users.';
$string['configdefaultrequestcategory'] = 'Courses requested by users will be automatically placed in this category.';
$string['configdefaultrequestedcategory'] = 'Default category to put courses that were requested into, if they\'re approved.';
$string['configdefaultuserroleid'] = 'All logged in users will be given the capabilities of the role you specify here, at the site level, in ADDITION to any other roles they may have been given. The default is the Authenticated user role. Note that this will not conflict with other roles they have unless you prohibit capabilities, it just ensures that all users have capabilities that are not assignable at the course level (eg post blog entries, manage own calendar, etc).';
@@ -229,7 +227,7 @@
$string['configenablerssfeeds'] = 'If enabled, RSS feeds are generated by various features across the site, such as blogs, forums, database activities and glossaries. Note that RSS feeds also need to be enabled for the particular activity modules.';
$string['configenablerssfeedsdisabled'] = 'It is not available because RSS feeds are disabled in all the Site. To enable them, go to the Variables settings under Admin Configuration.';
$string['configenablerssfeedsdisabled2'] = 'RSS feeds are currently disabled at site level. They may be enabled in Advanced features in the Site administration.';
-$string['configenablesafebrowserintegration'] = 'This adds the choice \'Require Safe Exam Browser\' to the \'Browser security\' field on the quiz settings form. See http://www.safeexambrowser.org/ for more information.';
+$string['configenablesafebrowserintegration'] = 'This adds the choice \'Require Safe Exam Browser\' to the \'Browser security\' field on the quiz settings form. See https://www.safeexambrowser.org/ for more information.';
$string['configenablestats'] = 'If you choose \'yes\' here, Moodle\'s cronjob will process the logs and gather some statistics. Depending on the amount of traffic on your site, this can take awhile. If you enable this, you will be able to see some interesting graphs and statistics about each of your courses, or on a sitewide basis.';
$string['configenabletrusttext'] = 'By default Moodle will always thoroughly clean text that comes from users to remove any possible bad scripts, media etc that could be a security risk. The Trusted Content system is a way of giving particular users that you trust the ability to include these advanced features in their content without interference. To enable this system, you need to first enable this setting, and then grant the Trusted Content permission to a specific Moodle role. Texts created or uploaded by such users will be marked as trusted and will not be cleaned before display.';
$string['configenablewebservices'] = 'Web services enable other systems to log in to this Moodle and perform operations. For extra security this feature should be disabled unless you are really using it.';
@@ -241,7 +239,7 @@
$string['configextramemorylimit'] = 'Some scripts like search, backup/restore or cron require more memory. Set higher values for large sites.';
$string['configfilterall'] = 'Filter all strings, including headings, titles, navigation bar and so on. This is mostly useful when using the multilang filter, otherwise it will just create extra load on your site for little gain.';
$string['configfiltermatchoneperpage'] = 'Automatic linking filters will only generate a single link for the first matching text instance found on the complete page. All others are ignored.';
-$string['configfiltermatchonepertext'] = 'Automatic linking filters will only generate a single link for the first matching text instance found in each item of text (e.g., resource, block) on the page. All others are ignored. This setting is ignored if the one per page setting is yes.';
+$string['configfiltermatchonepertext'] = 'Automatic linking filters will only generate a single link for the first matching text instance found in each item of text on the page. All others are ignored. This setting has no effect if \'Filter match once per page\' is enabled.';
$string['configfilteruploadedfiles'] = 'Process all uploaded HTML and text files with the filters before displaying them, only uploaded HTML files or none at all.';
$string['configforcelogin'] = 'Normally, the front page of the site and the course listings (but not courses) can be read by people without logging in to the site. If you want to force people to log in before they do ANYTHING on the site, then you should enable this setting.';
$string['configforceloginforprofiles'] = 'This setting forces people to log in as a real (non-guest) account before viewing any user\'s profile. If you disabled this setting, you may find that some users post advertising (spam) or other inappropriate content in their profiles, which is then visible to the whole world.';
@@ -252,7 +250,7 @@
$string['configfullnamedisplay'] = 'This defines how names are shown when they are displayed in full. The default value, "language", leaves it to the string "fullnamedisplay" in the current language pack to decide. Some languages have different name display conventions.
For most mono-lingual sites the most efficient setting is "firstname lastname", but you may choose to hide surnames altogether. Placeholders that can be used are: firstname, lastname, firstnamephonetic, lastnamephonetic, middlename, and alternatename.';
-$string['configgeoipfile'] = 'Location of GeoLite2 City binary data file. This file is not part of Moodle distribution and must be obtained separately from MaxMind. You can either buy a commercial version or use the free version. Simply download http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz and extract it into "{$a}" directory on your server.';
+$string['configgeoipfile'] = 'Location of GeoLite2 City binary data file. This file is not part of Moodle distribution and must be obtained separately from MaxMind. You can either buy a commercial version or use the free version. You\'ll need to register to download the City database file, which you can do at https://dev.maxmind.com/geoip/geoip2/geolite2/. Once you\'ve registered and downloaded the file, extract it into "{$a}" directory on your server.';
$string['configgetremoteaddrconf'] = 'If your server is behind a reverse proxy, you can use this setting to specify which HTTP headers can be trusted to contain the remote IP address. The headers are read in order, using the first one that is available.';
$string['configgradebookroles'] = 'This setting allows you to control who appears on the gradebook. Users need to have at least one of these roles in a course to be shown in the gradebook for that course.';
$string['configgradeexport'] = 'Choose which gradebook export formats are your primary methods for exporting grades. Chosen plugins will then set and use a "last exported" field for every grade. For example, this might result in exported records being identified as being "new" or "updated". If you are not sure about this then leave everything unchecked.';
@@ -456,7 +454,7 @@
$string['defaultcity'] = 'Default city';
$string['defaultcity_help'] = 'A city entered here will be the default city when creating new user accounts.';
$string['defaultformatnotset'] = 'Error determining default course format. Please check site settings.';
-$string['defaulthomepage'] = 'Default home page for users';
+$string['defaulthomepage'] = 'Home page for users';
$string['defaultrequestcategory'] = 'Default category for course requests';
$string['defaultsettinginfo'] = 'Default: {$a}';
$string['defaultuserroleid'] = 'Default role for all users';
@@ -520,7 +518,7 @@
$string['enabled'] = 'Enabled';
$string['enabledevicedetection'] = 'Enable device detection';
$string['enableglobalsearch'] = 'Enable global search';
-$string['enableglobalsearch_desc'] = 'If enabled, data will be indexed and syncronised by a scheduled task.';
+$string['enableglobalsearch_desc'] = 'If enabled, data will be indexed and synchronised by a scheduled task.';
$string['enablegravatar'] = 'Enable Gravatar';
$string['enablegravatar_help'] = 'When enabled Moodle will attempt to fetch a user profile picture from Gravatar if the user has not uploaded an image.';
$string['enablemobilewebservice'] = 'Enable web services for mobile devices';
@@ -654,11 +652,11 @@
$string['ipblocker'] = 'IP blocker';
$string['ipblockersyntax'] = 'Put every entry on one line. Valid entries are either full IP address (such as 192.168.10.1) which matches a single host; or partial address (such as 192.168) which matches any address starting with those numbers; or CIDR notation (such as 231.54.211.0/20); or a range of IP addresses (such as 231.3.56.10-20) where the range applies to the last part of the address. Text domain names (like \'example.com\') are not supported. Blank lines, and text following a "#" character are ignored.';
$string['iplookup'] = 'IP address lookup';
-$string['iplookupgeoplugin'] = 'geoPlugin service is currently being used to look up geographical information. For more accurate results we recommend installing a local copy of the MaxMind GeoLite database.';
+$string['iplookupgeoplugin'] = 'The geoPlugin service is currently being used to look up geographical information. For more accurate results we recommend installing a local copy of the MaxMind GeoLite database.';
$string['iplookupinfo'] = 'By default Moodle uses the free online NetGeo (The Internet Geographic Database) server to lookup location of IP addresses, unfortunately this database is not maintained anymore and may return wildly incorrect data.
It is recommended to install local copy of free GeoLite2 City database from MaxMind.
IP address location is displayed on simple map or using Google Maps. Please note that you need to have a Google account and apply for free Google Maps API key to enable interactive maps.';
-$string['iplookupmaxmindnote'] = 'This product includes GeoLite2 data created by MaxMind, available from http://www.maxmind.com.';
+$string['iplookupmaxmindnote'] = 'This product includes GeoLite2 data created by MaxMind, available from https://www.maxmind.com.';
$string['ishttpswarning'] = 'It has been detected that your site is not secured using HTTPS. It is strongly recommended to migrate your site to HTTPS for increased security and improved integration with other systems.';
$string['keeptagnamecase'] = 'Keep tag name casing';
$string['lang'] = 'Default language';
@@ -755,6 +753,7 @@
$string['maxusersperpage'] = ' Maximum users per page';
$string['configmaxusersperpage'] = 'Maximum number of users displayed within user selector in course, group, cohort, webservice etc.';
$string['mbstringrecommended'] = 'Installing the optional MBSTRING library is highly recommended in order to improve site performance, particularly if your site is supporting non-Latin languages.';
+$string['mbstringrequired'] = 'Installing the MBSTRING library is required in order to improve site performance, particularly if your site is supporting non-Latin languages.';
$string['mediapluginavi'] = 'Enable .avi filter';
$string['mediapluginflv'] = 'Enable .flv filter';
$string['mediapluginimg'] = 'Enable auto-embedding of linked images';
@@ -937,7 +936,7 @@
$string['profilefieldcolumns'] = 'Columns';
$string['profilefieldispassword'] = 'Is this a password field?';
$string['profilefieldlink'] = 'Link';
-$string['profilefieldlink_help'] = 'To transform the text into a link, enter a URL containing $$, where $$ will be replaced with the text. For example, to transform a Twitter ID to a link, enter http://twitter.com/$$.';
+$string['profilefieldlink_help'] = 'To transform the text into a link, enter a URL containing $$, where $$ will be replaced with the text. For example, to transform a Twitter ID to a link, enter https://twitter.com/$$.';
$string['profilefieldlinktarget'] = 'Link target';
$string['profilefieldmaxlength'] = 'Maximum length';
$string['profilefieldrows'] = 'Rows';
@@ -1004,21 +1003,24 @@
$string['recaptchaprivatekey'] = 'ReCAPTCHA secret key';
$string['recaptchapublickey'] = 'ReCAPTCHA site key';
$string['register'] = 'Register your site';
-$string['registermoodlenet'] = 'We\'d love to stay in touch and provide you with important things for your Moodle site!
By registering:
- You\'ll be one of the first to find out about important notifications such as security alerts and new Moodle releases.
- You can access and activate mobile push notifications from your Moodle site through our free Moodle app.
- You are contributing to our Moodle statistics of the worldwide community, which help us improve Moodle and our community sites.
- If you wish, your site can be included in the list of registered Moodle sites in your country.
';
+$string['registermoodlenet'] = 'We\'d love to stay in touch and provide you with important things for your Moodle site!
By registering:
- You can subscribe to receive notifications of new Moodle releases, security alerts and other important news.
- You can access and activate mobile push notifications from your Moodle site through our free Moodle app.
- You are contributing to our Moodle statistics of the worldwide community, which help us improve Moodle and our community sites.
- If you wish, your site can be included in the list of registered Moodle sites in your country.
';
$string['registermoodleorg'] = 'When you register your site';
$string['registermoodleorgli1'] = 'You are added to a low-volume mailing list for important notifications such as security alerts and new releases of Moodle.';
$string['registermoodleorgli2'] = 'Statistics about your site will be added to the {$a} of the worldwide Moodle community.';
$string['registerwithmoodleorg'] = 'Register your site';
$string['registration'] = 'Registration';
-$string['registration_help'] = 'It is recommended that you register your site in order to receive security alerts and access to Moodle.net, our course sharing platform.';
+$string['registration_help'] = 'By registering:
+
+* You will receive security alerts
+* You can activate mobile app push notifications from your site
+* You are contributing to our Moodle statistics of the worldwide community';
$string['registrationwarning'] = 'Your site is not yet registered.';
$string['registrationwarningcontactadmin'] = 'Your site is not yet registered. Please notify your administrator.';
$string['releasenoteslink'] = 'For information about this version of Moodle, please see the online Release Notes';
$string['rememberusername'] = 'Remember username';
$string['rememberusername_desc'] = 'Enable if you want to store permanent cookies with usernames during user login. Permanent cookies may be considered a privacy issue if used without consent.';
$string['reportsmanage'] = 'Manage reports';
-$string['requiredentrieschanged'] = 'IMPORTANT - PLEASE READ
(This warning message will only be displayed during this upgrade)
Due to a bug fix, the behaviour of database activities using the \'Required entries\' and \'Required entries before viewing settings\' settings will change. A more detailed explanation of the changes can be read on the database module forum. The expected behavior of these settings can also be read on Moodle Docs.
-
This change affects the following databases in your system: (Please save this list now, and after the upgrade, check that these activities still work the way that the teacher intends.)
{$a->text}
';
+$string['requiredentrieschanged'] = 'Note: After upgrading, the setting \'Required entries before viewing\' is now enforced in the following database activities:
{$a->text}
';
$string['requiremodintro'] = 'Require activity description';
$string['requiremodintro_desc'] = 'If enabled, users will be forced to enter a description for each activity.';
$string['requires'] = 'Requires';
@@ -1295,6 +1297,7 @@
$string['unicoderequired'] = 'It is required that you store all your data in Unicode format (UTF-8). New installations must be performed into databases that have their default character set as Unicode. If you are upgrading, you should perform the UTF-8 migration process (see the Admin page).';
$string['uninstallplugin'] = 'Uninstall';
$string['unlockaccount'] = 'Unlock account';
+$string['unoconvwarning'] = 'The version of unoconv you have installed is not supported.';
$string['unsettheme'] = 'Unset theme';
$string['unsupported'] = 'Unsupported';
$string['unsupporteddbfileformat'] = 'Your database uses Antelope as the file format. Full UTF-8 support in MySQL and MariaDB requires the Barracuda file format. Please switch to the Barracuda file format. See the documentation MySQL full unicode support for details.';
@@ -1306,6 +1309,7 @@
$string['unsupportedphpversion71'] = 'PHP version 7.1 is not supported.';
$string['unsupportedphpversion72'] = 'PHP version 7.2 is not supported.';
$string['unsupportedphpversion73'] = 'PHP version 7.3 is not supported.';
+$string['unsupportedphpversion74'] = 'PHP version 7.4 is not supported.';
$string['unsuspenduser'] = 'Activate user account';
$string['updateaccounts'] = 'Update existing accounts';
$string['updatecomponent'] = 'Update component';
@@ -1410,9 +1414,8 @@
// Deprecated since Moodle 3.3.
$string['loginpasswordautocomplete'] = 'Prevent password autocompletion on login form';
$string['loginpasswordautocomplete_help'] = 'If enabled, users are not allowed to save their account password in their browser.';
-$string['unoconvwarning'] = 'The version of unoconv you have installed is not supported.';
// Deprecated since Moodle 3.4
-$string['moodleorghubname'] = 'Moodle.net';
+$string['moodleorghubname'] = 'Moodle';
$string['hubs'] = 'Hubs';
$string['configloginhttps'] = 'Turning this on will make Moodle use a secure https connection just for the login page (providing a secure login), and then afterwards revert back to the normal http URL for general speed. CAUTION: this setting REQUIRES https to be specifically enabled on the web server - if it is not then YOU COULD LOCK YOURSELF OUT OF YOUR SITE.';
$string['loginhttps'] = 'Use HTTPS for logins';
diff --git a/lang/en/auth.php b/lang/en/auth.php
index 1233c20838d18..4f76b92687dbc 100644
--- a/lang/en/auth.php
+++ b/lang/en/auth.php
@@ -51,7 +51,7 @@
$string['auth_remove_suspend'] = 'Suspend internal';
$string['auth_remove_user'] = 'Specify what to do with internal user account during mass synchronisation when user was removed from external source. Only suspended users are automatically restored if they reappear in the external source.';
$string['auth_remove_user_key'] = 'Removed ext user';
-$string['auth_sync_suspended'] = 'When enabled, the suspended attribute will be used to update the local user account\'s suspension status.';
+$string['auth_sync_suspended'] = 'If enabled, the suspended attribute will be used to update the local user account\'s suspension status.';
$string['auth_sync_suspended_key'] = 'Synchronise local user suspension status';
$string['auth_sync_script'] = 'User account synchronisation';
$string['auth_updatelocal'] = 'Update local';
diff --git a/lang/en/availability.php b/lang/en/availability.php
index c92b544f827b8..e6620e2d95789 100644
--- a/lang/en/availability.php
+++ b/lang/en/availability.php
@@ -28,7 +28,7 @@
$string['condition_group'] = 'Restriction set';
$string['condition_group_info'] = 'Add a set of nested restrictions to apply complex logic.';
$string['enableavailability'] = 'Enable restricted access';
-$string['enableavailability_desc'] = 'When enabled, this lets you set conditions (based on date, grade, or completion) that control whether an activity or resource can be accessed.';
+$string['enableavailability_desc'] = 'If enabled, conditions (based on date, grade, completion etc.) may be set to control whether an activity or resource can be accessed.';
$string['error_list_nochildren'] = 'Restriction sets should contain at least one condition.';
$string['hidden_marker'] = '(hidden otherwise)';
$string['hidden_individual'] = 'Hidden entirely if user does not meet this condition';
diff --git a/lang/en/badges.php b/lang/en/badges.php
index 5072cd71fedfb..4512e98653ae6 100644
--- a/lang/en/badges.php
+++ b/lang/en/badges.php
@@ -111,7 +111,7 @@
$string['backpackemailverificationpending'] = 'Verification pending';
$string['backpackemailverifyemailbody'] = 'Hi,
-A new connection to your OpenBadges backpack has been requested from \'{$a->sitename}\' using your email address.
+A new connection to your badges backpack has been requested from \'{$a->sitename}\' using your email address.
To confirm and activate the connection to your backpack, please go to
@@ -121,7 +121,7 @@
If you need help, please contact the site administrator,
{$a->admin}';
-$string['backpackemailverifyemailsubject'] = '{$a}: OpenBadges Backpack email verification';
+$string['backpackemailverifyemailsubject'] = '{$a}: Badges backpack email verification';
$string['backpackemailverifypending'] = 'A verification email has been sent to {$a}. Click on the verification link in the email to activate your Backpack connection.';
$string['backpackemailverifysuccess'] = 'Thanks for verifying your email address. You are now connected to your backpack.';
$string['backpackemailverifytokenmismatch'] = 'The token in the link you clicked does not match the stored token. Make sure you clicked the link in most recent email you received.';
@@ -176,7 +176,7 @@
$string['clearsettings'] = 'Clear settings';
$string['completionnotenabled'] = 'Course completion is not enabled for this course, so it cannot be included in badge criteria. Course completion may be enabled in the course settings.';
$string['completioninfo'] = 'This badge was issued for completing: ';
-$string['configenablebadges'] = 'When enabled, this feature lets you create badges and award them to site users.';
+$string['configenablebadges'] = 'If enabled, this feature lets you create badges and award them to site users.';
$string['configuremessage'] = 'Badge message';
$string['connect'] = 'Connect';
$string['connected'] = 'Connected';
@@ -569,7 +569,6 @@
// Deprecated since Moodle 3.6.
$string['error:invalidbadgeurl'] = 'Invalid issuer URL format. The URL should have a prefix http:// or https://.';
$string['backpackbadges'] = 'You have {$a->totalbadges} badge(s) displayed from {$a->totalcollections} collection(s). Change backpack settings.';
-$string['error:nogroups'] = 'There are no public collections of badges available in your backpack.
-Only public collections are shown. Visit your backpack to create some public collections.
';
+$string['error:nogroups'] = 'There are no public collections of badges available in your backpack.
Only public collections are shown. Visit your backpack to create some public collections.
';
$string['nobackpackbadges'] = 'There are no badges in the collections you have selected. Add more collections.';
$string['nobackpackcollections'] = 'No badge collections have been selected. Add collections.';
diff --git a/lang/en/calendar.php b/lang/en/calendar.php
index 8a0f70350e5a5..092ad4b90c35c 100644
--- a/lang/en/calendar.php
+++ b/lang/en/calendar.php
@@ -110,6 +110,7 @@
$string['eventsdeleted'] = 'Events deleted';
$string['eventsimported'] = 'Events imported: {$a}';
$string['eventsource'] = 'Event source';
+$string['eventsskipped'] = 'Events skipped: {$a}';
$string['eventsupdated'] = 'Events updated: {$a}';
$string['eventsfor'] = '{$a} events';
$string['eventskey'] = 'Events key';
@@ -258,6 +259,7 @@
$string['user'] = 'User';
$string['userevent'] = 'User event';
$string['userevents'] = 'User events';
+$string['viewupcomingactivitiesdue'] = 'View the upcoming activities due';
$string['wed'] = 'Wed';
$string['wednesday'] = 'Wednesday';
$string['weekly'] = 'Weekly';
diff --git a/lang/en/completion.php b/lang/en/completion.php
index 94894dfd2e0a6..23b5b007b8ca5 100644
--- a/lang/en/completion.php
+++ b/lang/en/completion.php
@@ -112,7 +112,7 @@
$string['completionview'] = 'Require view';
$string['completionview_desc'] = 'Student must view this activity to complete it';
$string['configcompletiondefault'] = 'The default setting for completion tracking when creating new activities.';
-$string['configenablecompletion'] = 'When enabled, this lets you turn on completion tracking (progress) features at course level.';
+$string['configenablecompletion'] = 'If enabled, course and activity completion conditions may be set. Setting activity completion conditions is recommended so that meaningful data is displayed for users in their course overview on the Dashboard.';
$string['confirmselfcompletion'] = 'Confirm self completion';
$string['courseaggregation'] = 'Condition requires';
$string['courseaggregation_all'] = 'ALL selected courses to be completed';
@@ -148,7 +148,7 @@
$string['err_nocourses'] = 'Course completion is not enabled for any other courses, so none can be displayed. You can enable course completion in the course settings.';
$string['err_nograde'] = 'A course pass grade has not been set for this course. To enable this criteria type you must create a pass grade for this course.';
$string['err_noroles'] = 'There are no roles with the capability moodle/course:markcomplete in this course.';
-$string['err_nousers'] = 'There are no students on this course or group for whom completion information is displayed. (By default, completion information is displayed only for students, so if there are no students, you will see this error. Administrators can alter this option via the admin screens.)';
+$string['err_nousers'] = 'There are no students in this course or group for whom completion information is displayed. (Completion information is displayed only for users with the capability \'Be shown on completion reports\'. The capability is allowed for the default role of student only, so if there are no students, you will see this message.)';
$string['err_settingslocked'] = 'One or more students have already completed a criterion so the settings have been locked. Unlocking the completion criteria settings will delete any existing user data and may cause confusion.';
$string['err_system'] = 'An internal error occurred in the completion system. (System administrators can enable debugging information to see more detail.)';
$string['eventcoursecompleted'] = 'Course completed';
diff --git a/lang/en/countries.php b/lang/en/countries.php
index 2c2e57cbcbdf2..9b206cd099791 100644
--- a/lang/en/countries.php
+++ b/lang/en/countries.php
@@ -25,7 +25,7 @@
$string['AD'] = 'Andorra';
$string['AE'] = 'United Arab Emirates';
$string['AF'] = 'Afghanistan';
-$string['AG'] = 'Antigua And Barbuda';
+$string['AG'] = 'Antigua and Barbuda';
$string['AI'] = 'Anguilla';
$string['AL'] = 'Albania';
$string['AM'] = 'Armenia';
@@ -38,7 +38,7 @@
$string['AW'] = 'Aruba';
$string['AX'] = 'Åland Islands';
$string['AZ'] = 'Azerbaijan';
-$string['BA'] = 'Bosnia And Herzegovina';
+$string['BA'] = 'Bosnia and Herzegovina';
$string['BB'] = 'Barbados';
$string['BD'] = 'Bangladesh';
$string['BE'] = 'Belgium';
@@ -50,8 +50,8 @@
$string['BL'] = 'Saint Barthélemy';
$string['BM'] = 'Bermuda';
$string['BN'] = 'Brunei Darussalam';
-$string['BO'] = 'Bolivia, Plurinational State Of';
-$string['BQ'] = 'Bonaire, Sint Eustatius And Saba';
+$string['BO'] = 'Bolivia (Plurinational State of)';
+$string['BQ'] = 'Bonaire, Sint Eustatius and Saba';
$string['BR'] = 'Brazil';
$string['BS'] = 'Bahamas';
$string['BT'] = 'Bhutan';
@@ -61,7 +61,7 @@
$string['BZ'] = 'Belize';
$string['CA'] = 'Canada';
$string['CC'] = 'Cocos (Keeling) Islands';
-$string['CD'] = 'Congo, The Democratic Republic Of The';
+$string['CD'] = 'Congo (the Democratic Republic of the)';
$string['CF'] = 'Central African Republic';
$string['CG'] = 'Congo';
$string['CH'] = 'Switzerland';
@@ -94,7 +94,7 @@
$string['FI'] = 'Finland';
$string['FJ'] = 'Fiji';
$string['FK'] = 'Falkland Islands (Malvinas)';
-$string['FM'] = 'Micronesia, Federated States Of';
+$string['FM'] = 'Micronesia (Federated States of)';
$string['FO'] = 'Faroe Islands';
$string['FR'] = 'France';
$string['GA'] = 'Gabon';
@@ -111,13 +111,13 @@
$string['GP'] = 'Guadeloupe';
$string['GQ'] = 'Equatorial Guinea';
$string['GR'] = 'Greece';
-$string['GS'] = 'South Georgia And The South Sandwich Islands';
+$string['GS'] = 'South Georgia and the South Sandwich Islands';
$string['GT'] = 'Guatemala';
$string['GU'] = 'Guam';
$string['GW'] = 'Guinea-Bissau';
$string['GY'] = 'Guyana';
$string['HK'] = 'Hong Kong';
-$string['HM'] = 'Heard Island And Mcdonald Islands';
+$string['HM'] = 'Heard Island and McDonald Islands';
$string['HN'] = 'Honduras';
$string['HR'] = 'Croatia';
$string['HT'] = 'Haiti';
@@ -125,11 +125,11 @@
$string['ID'] = 'Indonesia';
$string['IE'] = 'Ireland';
$string['IL'] = 'Israel';
-$string['IM'] = 'Isle Of Man';
+$string['IM'] = 'Isle of Man';
$string['IN'] = 'India';
$string['IO'] = 'British Indian Ocean Territory';
$string['IQ'] = 'Iraq';
-$string['IR'] = 'Iran, Islamic Republic Of';
+$string['IR'] = 'Iran (Islamic Republic of)';
$string['IS'] = 'Iceland';
$string['IT'] = 'Italy';
$string['JE'] = 'Jersey';
@@ -141,9 +141,9 @@
$string['KH'] = 'Cambodia';
$string['KI'] = 'Kiribati';
$string['KM'] = 'Comoros';
-$string['KN'] = 'Saint Kitts And Nevis';
-$string['KP'] = 'Korea, Democratic People\'s Republic Of';
-$string['KR'] = 'Korea, Republic Of';
+$string['KN'] = 'Saint Kitts and Nevis';
+$string['KP'] = 'Korea (the Democratic People\'s Republic of)';
+$string['KR'] = 'Korea (the Republic of)';
$string['KW'] = 'Kuwait';
$string['KY'] = 'Cayman Islands';
$string['KZ'] = 'Kazakhstan';
@@ -160,12 +160,12 @@
$string['LY'] = 'Libya';
$string['MA'] = 'Morocco';
$string['MC'] = 'Monaco';
-$string['MD'] = 'Moldova, Republic Of';
+$string['MD'] = 'Moldova (the Republic of)';
$string['ME'] = 'Montenegro';
-$string['MF'] = 'Saint Martin (French Part)';
+$string['MF'] = 'Saint Martin (French part)';
$string['MG'] = 'Madagascar';
$string['MH'] = 'Marshall Islands';
-$string['MK'] = 'Macedonia, The Former Yugoslav Republic Of';
+$string['MK'] = 'North Macedonia';
$string['ML'] = 'Mali';
$string['MM'] = 'Myanmar';
$string['MN'] = 'Mongolia';
@@ -201,10 +201,10 @@
$string['PH'] = 'Philippines';
$string['PK'] = 'Pakistan';
$string['PL'] = 'Poland';
-$string['PM'] = 'Saint Pierre And Miquelon';
+$string['PM'] = 'Saint Pierre and Miquelon';
$string['PN'] = 'Pitcairn';
$string['PR'] = 'Puerto Rico';
-$string['PS'] = 'Palestine, State Of';
+$string['PS'] = 'Palestine, State of';
$string['PT'] = 'Portugal';
$string['PW'] = 'Palau';
$string['PY'] = 'Paraguay';
@@ -220,9 +220,9 @@
$string['SD'] = 'Sudan';
$string['SE'] = 'Sweden';
$string['SG'] = 'Singapore';
-$string['SH'] = 'Saint Helena, Ascension And Tristan Da Cunha';
+$string['SH'] = 'Saint Helena, Ascension and Tristan da Cunha';
$string['SI'] = 'Slovenia';
-$string['SJ'] = 'Svalbard And Jan Mayen';
+$string['SJ'] = 'Svalbard and Jan Mayen';
$string['SK'] = 'Slovakia';
$string['SL'] = 'Sierra Leone';
$string['SM'] = 'San Marino';
@@ -230,12 +230,12 @@
$string['SO'] = 'Somalia';
$string['SR'] = 'Suriname';
$string['SS'] = 'South Sudan';
-$string['ST'] = 'Sao Tome And Principe';
+$string['ST'] = 'Sao Tome and Principe';
$string['SV'] = 'El Salvador';
-$string['SX'] = 'Sint Maarten (Dutch Part)';
+$string['SX'] = 'Sint Maarten (Dutch part)';
$string['SY'] = 'Syrian Arab Republic';
-$string['SZ'] = 'Swaziland';
-$string['TC'] = 'Turks And Caicos Islands';
+$string['SZ'] = 'Eswatini';
+$string['TC'] = 'Turks and Caicos Islands';
$string['TD'] = 'Chad';
$string['TF'] = 'French Southern Territories';
$string['TG'] = 'Togo';
@@ -247,24 +247,24 @@
$string['TN'] = 'Tunisia';
$string['TO'] = 'Tonga';
$string['TR'] = 'Turkey';
-$string['TT'] = 'Trinidad And Tobago';
+$string['TT'] = 'Trinidad and Tobago';
$string['TV'] = 'Tuvalu';
$string['TW'] = 'Taiwan';
-$string['TZ'] = 'Tanzania, United Republic Of';
+$string['TZ'] = 'Tanzania, the United Republic of';
$string['UA'] = 'Ukraine';
$string['UG'] = 'Uganda';
$string['UM'] = 'United States Minor Outlying Islands';
$string['US'] = 'United States';
$string['UY'] = 'Uruguay';
$string['UZ'] = 'Uzbekistan';
-$string['VA'] = 'Holy See (Vatican City State)';
-$string['VC'] = 'Saint Vincent And The Grenadines';
-$string['VE'] = 'Venezuela, Bolivarian Republic Of';
-$string['VG'] = 'Virgin Islands, British';
-$string['VI'] = 'Virgin Islands, U.S.';
+$string['VA'] = 'Holy See';
+$string['VC'] = 'Saint Vincent and the Grenadines';
+$string['VE'] = 'Venezuela (Bolivarian Republic of)';
+$string['VG'] = 'Virgin Islands (British)';
+$string['VI'] = 'Virgin Islands (U.S.)';
$string['VN'] = 'Viet Nam';
$string['VU'] = 'Vanuatu';
-$string['WF'] = 'Wallis And Futuna';
+$string['WF'] = 'Wallis and Futuna';
$string['WS'] = 'Samoa';
$string['YE'] = 'Yemen';
$string['YT'] = 'Mayotte';
diff --git a/lang/en/error.php b/lang/en/error.php
index 825a6b3529454..7fe328446dd4b 100644
--- a/lang/en/error.php
+++ b/lang/en/error.php
@@ -96,7 +96,7 @@
$string['cannotfindlang'] = 'Cannot find "{$a}" language pack!';
$string['cannotfindteacher'] = 'Cannot find teacher';
$string['cannotfinduser'] = 'Cannot find user named "{$a}"';
-$string['cannotgeoplugin'] = 'Cannot connect to geoPlugin server at http://www.geoplugin.com, please check proxy settings or better install MaxMind GeoLite City data file';
+$string['cannotgeoplugin'] = 'Cannot connect to the geoPlugin server at https://www.geoplugin.com. Please check your proxy settings or install the MaxMind GeoLite City data file.';
$string['cannotgetblock'] = 'Could not retrieve blocks from the database';
$string['cannotgetcats'] = 'Cannot get category record';
$string['cannotgetdata'] = 'Cannot get data';
@@ -169,7 +169,7 @@
$string['cannotuseadminadminorteacher'] = 'You need to be a teacher or admin user to use this page';
$string['cannotusepage'] = 'Only teachers and administrators can use this page';
$string['cannotusepage2'] = 'Sorry, you may not use this page';
-$string['cannotviewcategory'] = 'You don\'t have permission to view courses here';
+$string['cannotviewcategory'] = 'You don\'t have permission to view this list of courses.';
$string['cannotviewprofile'] = 'You cannot view the profile of this user';
$string['cannotviewreport'] = 'You cannot view this report';
$string['cannotwritefile'] = 'Cannot write to file ({$a})';
@@ -263,6 +263,7 @@
$string['filternotenabled'] = 'Filter not enabled!';
$string['filternotinstalled'] = 'Filter {$a} is not currently installed';
$string['forumblockingtoomanyposts'] = 'You have exceeded the posting threshold set for this forum';
+$string['functionalityremoved'] = 'You are trying to access functionality that has been removed.';
$string['generalexceptionmessage'] = 'Exception - {$a}';
$string['gradepubdisable'] = 'Grade publishing disabled';
$string['gradesneedregrading'] = 'The course grades need to be recalculated';
@@ -384,7 +385,7 @@
$string['maxbytesfile'] = 'The file {$a->file} is too large. The maximum size you can upload is {$a->size}.';
$string['maxareabytes'] = 'The file is larger than the space remaining in this area.';
$string['messagingdisable'] = 'Messaging is disabled on this site';
-$string['mimetexisnotexist'] = 'Your system is not configured to run mimeTeX. You need to obtain the C source from http://www.forkosh.com/mimetex.zip, compile it and put the executable into your moodle/filter/tex/ directory.';
+$string['mimetexisnotexist'] = 'Your system is not configured to run mimeTeX. You need to obtain the C source from https://www.forkosh.com/mimetex.zip, compile it and put the executable into your moodle/filter/tex/ directory.';
$string['mimetexnotexecutable'] = 'Custom mimetex is not executable!';
$string['missingfield'] = 'Field "{$a}" is missing';
$string['missingkeyinsql'] = 'ERROR: missing param "{$a}" in query';
diff --git a/lang/en/grading.php b/lang/en/grading.php
index d19e3ff610ff2..46e3c27eda1ad 100644
--- a/lang/en/grading.php
+++ b/lang/en/grading.php
@@ -30,7 +30,7 @@
$string['changeactivemethod'] = 'Change active grading method to';
$string['clicktoclose'] = 'click to close';
$string['exc_gradingformelement'] = 'Unable to instantiate grading form element';
-$string['formnotavailable'] = 'Advanced grading method was selected to use but the grading form is not available yet. You may need to define it first via a link in the Administration block.';
+$string['formnotavailable'] = 'An advanced grading method was selected to use but the grading form is not available yet. You may need to define it first via a link in the actions menu or administration block.';
$string['gradingformunavailable'] = 'Please note: the advanced grading form is not ready at the moment. Simple grading method will be used until the form has a valid status.';
$string['gradingmanagement'] = 'Advanced grading';
$string['gradingmanagementtitle'] = 'Advanced grading: {$a->component} ({$a->area})';
diff --git a/lang/en/group.php b/lang/en/group.php
index 9d448ec385d48..9f32f85f89049 100644
--- a/lang/en/group.php
+++ b/lang/en/group.php
@@ -196,3 +196,4 @@
$string['usercount'] = 'User count';
$string['usercounttotal'] = 'User count ({$a})';
$string['usergroupmembership'] = 'Selected user\'s membership:';
+$string['memberofgroup'] = 'Group member of: {$a}';
diff --git a/lang/en/hub.php b/lang/en/hub.php
index e607eeed85325..d1ab5d37c2f04 100644
--- a/lang/en/hub.php
+++ b/lang/en/hub.php
@@ -82,7 +82,7 @@
$string['errorcourseinfo'] = 'An error occurred when retrieving course metadata from {$a}. Please try again to retrieve the course metadata by reloading this page later. Otherwise you can decide to continue the registration process with the following default metadata. ';
$string['errorcoursepublish'] = 'An error occurred during the course publication ({$a}). Please try again later.';
$string['errorcoursewronglypublished'] = 'A publication error has been returned by Moodle.net. Please try again later.';
-$string['errorotherhubsnotsupported'] = 'This page can no longer be used for registration with sites other than Moodle.net';
+$string['errorotherhubsnotsupported'] = 'This page can no longer be used for registration with custom sites directories.';
$string['errorregistration'] = 'An error occurred during registration, please try again later. ({$a})';
$string['errorunpublishcourses'] = 'Due to an unexpected error, the courses could not be deleted from Moodle.net. Try again later (recommended) or contact Moodle.net administrator.';
$string['errorws'] = '{$a}';
@@ -119,7 +119,7 @@
$string['operation'] = 'Actions';
$string['participantnumberaverage'] = 'Average number of participants ({$a})';
$string['policyagreed'] = 'Privacy notice and data processing agreement';
-$string['policyagreeddesc'] = 'I agree to the Privacy notice and data processing agreement for Moodle.net';
+$string['policyagreeddesc'] = 'I agree to the Privacy notice and data processing agreement';
$string['postaladdress'] = 'Postal address';
$string['postaladdress_help'] = 'Postal address of this site, or of the entity represented by this site.';
$string['postsnumber'] = 'Number of posts ({$a})';
@@ -140,6 +140,19 @@
$string['registereduserdevices'] = 'Number of users with registered mobile devices ({$a})';
$string['registeredactiveuserdevices'] = 'Number of active users with registered mobile devices which are receiving notifications ({$a})';
$string['registersite'] = 'Register with {$a}';
+$string['registerwithmoodleorg'] = 'Register your site';
+$string['registerwithmoodleorgupdate'] = 'Update your site registration';
+$string['registerwithmoodleorgcomplete'] = 'Complete your site registration';
+$string['registerwithmoodleorginfo'] = 'We\'d love to stay in touch and provide you with important things for your Moodle site! By registering:
+
+* You can subscribe to receive notifications of new Moodle releases, security alerts and other important news.
+* You can access and activate mobile push notifications from your Moodle site through our free Moodle app.
+* You are contributing to our Moodle statistics of the worldwide community, which help us improve Moodle and our community sites.
+* If you wish, your site can be included in the list of registered Moodle sites in your country.';
+$string['registerwithmoodleorginfoapp'] = 'About the Moodle app';
+$string['registerwithmoodleorginfostats'] = 'Moodle statistics';
+$string['registerwithmoodleorginfosites'] = 'Other sites in my country';
+$string['registerwithmoodleorgremove'] = 'Unregistering your site';
$string['registrationconfirmed'] = 'Site registration confirmed';
$string['registrationconfirmedon'] = 'Thank you for registering your site. Registration information will be kept up to date by the \'Site registration\' scheduled task.';
$string['removefromhub'] = 'Remove from Moodle.net';
@@ -161,10 +174,10 @@
$string['sharepublication_help'] = 'A backup of this course will be available on Moodle.net for people to restore and use on their own site.';
$string['siteadmin'] = 'Administrator';
$string['siteadmin_help'] = 'The full name of the site administrator.';
-$string['sitecommnews'] = 'Updates about Moodle news and features';
-$string['sitecommnews_help'] = 'You have the option of subscribing to our low volume email list including a newsletter about happenings in the Moodle community. ';
-$string['sitecommnewsno'] = 'No, I do not want to receive any email from Moodle HQ';
-$string['sitecommnewsyes'] = 'Yes please, include me in Moodle’s regular e-newsletter updates';
+$string['sitecommnews'] = 'Moodle newsletter';
+$string['sitecommnews_help'] = 'You have the option of subscribing to our Moodle newsletter. You may unsubscribe at any time.';
+$string['sitecommnewsno'] = 'No, I do not wish to receive any emails';
+$string['sitecommnewsyes'] = 'Yes, I would like to receive the Moodle newsletter';
$string['sitecountry'] = 'Country';
$string['sitecountry_help'] = 'The country your organisation or institution is located in.';
$string['sitedesc'] = 'Description';
@@ -186,8 +199,8 @@
$string['siteprivacylinked'] = 'Display my site name with the link';
$string['siteregistrationcontact'] = 'Display contact form';
$string['siteregistrationcontact_help'] = 'If you allow it, other people in our Moodle community (who need a login account) can contact you via a form on our Moodle community site. However, they will never be able to see your email address.';
-$string['siteregistrationemail'] = 'Notifications about important security and technical issues.';
-$string['siteregistrationemail_help'] = 'You have the option of subscribing to our low volume email list for important news (on security issues or new releases).';
+$string['siteregistrationemail'] = 'Notifications of new Moodle releases, security alerts and other important news';
+$string['siteregistrationemail_help'] = 'You have the option of subscribing to our low-volume mailing list for notifications of new Moodle releases, security alerts and other important news. You may unsubscribe at any time.';
$string['siteregistrationupdated'] = 'Site registration updated';
$string['siterelease'] = 'Moodle release';
$string['sitereleasenum'] = 'Moodle release ({$a})';
@@ -215,15 +228,16 @@
$string['unregistrationerror'] = 'An error occurred when the site tried to unregister from Moodle.net: {$a}';
$string['update'] = 'Update';
$string['updatesite'] = 'Update registration on {$a}';
+$string['updatesiteregistration'] = 'Update registration';
$string['updatestatus'] = 'Check it now.';
$string['usedifferentemail'] = 'Use different email';
-$string['unregisterexplained'] = 'If the site with URL {$a} is registered on Moodle.net its registration will be removed.';
-$string['urlalreadyregistered'] = 'Your site seems to be already registered on Moodle.net, which means something has gone wrong. Please contact the Moodle.net administrator to reset your registration so you can try again.';
+$string['unregisterexplained'] = 'If the site with URL {$a} is registered, then its registration will be removed.';
+$string['urlalreadyregistered'] = 'Your site seems to be already registered, which means something has gone wrong. Please contact the Moodle.net administrator to reset your registration so you can try again.';
$string['usersnumber'] = 'Number of users ({$a})';
$string['wrongtoken'] = 'The registration failed for some unknown reason (network?). Please try again.';
// Deprecated since Moodle 3.4.
-$string['registermoochtips'] = 'Register your site with Moodle to get security alerts and access to Moodle.net, our course sharing platform.';
+$string['registermoochtips'] = 'By registering, you will receive security alerts, can activate mobile app push notifications from your site, and are contributing to our Moodle statistics of the worldwide community.';
$string['errorcronnoxmlrpc'] = 'XML-RPC must be enabled in order to update the registration.';
$string['advertiseonhub'] = 'Share this course for people to join';
$string['advertiseonmoodleorg'] = 'Advertise this course on moodle.org';
diff --git a/lang/en/install.php b/lang/en/install.php
index 98a021a587db1..cd7e2fbdfd107 100644
--- a/lang/en/install.php
+++ b/lang/en/install.php
@@ -144,6 +144,7 @@
$string['inputwebadress'] = 'Web address :';
$string['inputwebdirectory'] = 'Moodle directory:';
$string['installation'] = 'Installation';
+$string['invaliddbprefix'] = 'Invalid prefix. The prefix can only consist of lower case letters and underscore.';
$string['langdownloaderror'] = 'Unfortunately the language "{$a}" could not be downloaded. The installation process will continue in English.';
$string['langdownloadok'] = 'The language "{$a}" was installed successfully. The installation process will continue in this language.';
$string['memorylimit'] = 'Memory limit';
@@ -240,10 +241,7 @@
$string['welcomep30'] = 'This release of the {$a->installername} includes the applications
to create an environment in which Moodle will operate, namely:';
$string['welcomep40'] = 'The package also includes Moodle {$a->moodlerelease} ({$a->moodleversion}).';
-$string['welcomep50'] = 'The use of all the applications in this package is governed by their respective
- licences. The complete {$a->installername} package is
- open source and is distributed
- under the GPL license.';
+$string['welcomep50'] = 'The use of all the applications in this package is governed by their respective licences. The complete {$a->installername} package is open source and is distributed under the GPL license.';
$string['welcomep60'] = 'The following pages will lead you through some easy to follow steps to
configure and set up Moodle on your computer. You may accept the default
settings or, optionally, amend them to suit your own needs.';
diff --git a/lang/en/message.php b/lang/en/message.php
index 8fd31fc766c3e..e7b4d215e478f 100644
--- a/lang/en/message.php
+++ b/lang/en/message.php
@@ -100,8 +100,8 @@
$string['messageoutputs'] = 'Notification plugins';
$string['messagepreferences'] = 'Message preferences';
$string['message'] = 'Message';
-$string['messagecontactrequestsnotification'] = '{$a} wants to be added as a contact';
-$string['messagecontactrequestsnotificationsubject'] = '{$a} wants to be added as a contact';
+$string['messagecontactrequestsnotification'] = '{$a} is requesting to be added as a contact.';
+$string['messagecontactrequestsnotificationsubject'] = 'Contact request from {$a}';
$string['messagedrawerviewcontact'] = 'User details for {$a}';
$string['messagedrawerviewcontacts'] = 'Message contacts';
$string['messagedrawerviewconversation'] = 'Conversation with {$a}';
diff --git a/lang/en/mnet.php b/lang/en/mnet.php
index 8bcdb2aa1d536..bb5711180a72d 100644
--- a/lang/en/mnet.php
+++ b/lang/en/mnet.php
@@ -58,7 +58,7 @@
$string['duplicate_usernames'] = 'We failed to create an index on the columns "mnethostid" and "username" in your user table.
This can occur when you have duplicate usernames in your user table.
Your upgrade should still complete successfully. Click on the link above, and instructions on fixing this problem will appear in a new window. You can attend to that at the end of the upgrade.
';
$string['enabled_for_all'] = '(This service has been enabled for all hosts).';
$string['enterausername'] = 'Please enter a username, or a list of usernames separated by commas.';
-$string['error7020'] = 'This error normally occurs if the remote site has created a record for you with the wrong wwwroot, for example, http://yoursite.com instead of http://www.yoursite.com. You should contact the administrator of the remote site with your wwwroot (as specified in config.php) asking her to update her record for your host.';
+$string['error7020'] = 'This error normally occurs if the remote site has created a record for you with the wrong wwwroot, for example, https://yoursite.com instead of https://www.yoursite.com. Please contact the administrator of the remote site with your wwwroot (as specified in config.php) and ask them to update the record for your host.';
$string['error7022'] = 'The message you sent to the remote site was encrypted properly, but not signed. This is very unexpected; you should probably file a bug if this occurs (giving as much information as possible about the application versions in question etc).';
$string['error7023'] = 'The remote site has tried to decrypt your message with all the keys it has on record for your site. They have all failed. You might be able to fix this problem by manually re-keying with the remote site. This is unlikely to occur unless you\'ve been out of communication with the remote site for a few months.';
$string['error7024'] = 'You send an unencrypted message to the remote site, but the remote site doesn\'t accept unencrypted communication from your site. This is very unexpected; you should probably file a bug if this occurs (giving as much information as possible about the application versions in question, etc.';
diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index df841d662f3ca..a896601ede59c 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -194,7 +194,7 @@
$string['backuploglaststatus'] = 'Last execution log';
$string['backupmissinguserinfoperms'] = 'Note: This backup contains no user data. Exercise and Workshop activities will not be included in the backup, since these modules are not compatible with this type of backup.';
$string['backupnext'] = 'Next backup';
-$string['backupnonisowarning'] = 'Warning: this backup is from a non-Unicode version of Moodle (pre 1.6). If this backup contains any non-ISO-8859-1 texts then they may be CORRUPTED if you try to restore them to this Unicode version of Moodle. See the Backup FAQ for more information about how to recover this backup correctly.';
+$string['backupnonisowarning'] = 'Warning: this backup is from a non-Unicode version of Moodle (pre 1.6). If this backup contains any non-ISO-8859-1 texts then they may be CORRUPTED if you try to restore them to this Unicode version of Moodle. See the Backup FAQ for more information about how to recover this backup correctly.';
$string['backupnotyetrun'] = 'Automated backup pending';
$string['backuporiginalname'] = 'Backup name';
$string['backuproleassignments'] = 'Backup role assignments for these roles';
@@ -381,12 +381,11 @@
$string['coursesmovedout'] = 'Courses moved out from {$a}';
$string['coursespending'] = 'Courses pending approval';
$string['coursesearch'] = 'Search courses';
-$string['coursesearch_help'] = 'You can search for multiple words at once and can refine your search as follows:
-
-- word - find any match of this word within the text.
-- +word - only exact matching words will be found.
-- -word - don\'t include results containing this word.
-
';
+$string['coursesearch_help'] = 'You can search for multiple words at once and can refine your search as follows:
+
+* word - find any match of this word within the text
+* +word - only exact matching words will be found
+* -word - don\'t include results containing this word.';
$string['coursestart'] = 'Course start';
$string['coursesummary'] = 'Course summary';
$string['coursesummary_help'] = 'The course summary is displayed in the list of courses. A course search searches course summary text in addition to course names.';
@@ -885,36 +884,24 @@
$string['geolocation'] = 'latitude - longitude';
$string['gettheselogs'] = 'Get these logs';
$string['go'] = 'Go';
-$string['gpl'] = 'Copyright (C) 1999 onwards Martin Dougiamas (http://moodle.com)
+$string['gpl'] = 'Copyright (C) 1999 onwards Martin Dougiamas (https://moodle.com)
-This program 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 2 of the License, or
-(at your option) any later version.
+This program 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 2 of the License, or (at your option) any later version.
-This program 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.
+This program 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 Moodle License information page for full details:
-http://docs.moodle.org/dev/License';
+See the Moodle License information page for full details: https://docs.moodle.org/dev/License';
$string['gpllicense'] = 'GPL license';
-$string['gpl3'] = 'Copyright (C) 1999 onwards Martin Dougiamas (http://moodle.com)
+$string['gpl3'] = 'Copyright (C) 1999 onwards Martin Dougiamas (https://moodle.com)
-This program 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.
+This program 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.
-This program 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.
+This program 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 Moodle License information page for full details:
-http://docs.moodle.org/dev/License';
+See the Moodle License information page for full details: https://docs.moodle.org/dev/License';
$string['grade'] = 'Grade';
$string['grades'] = 'Grades';
-$string['gravatarenabled'] = 'Gravatar has been enabled for this site. If you don\'t upload a profile picture Moodle will attempt to load a profile picture for you from Gravatar.';
+$string['gravatarenabled'] = 'Gravatar has been enabled for this site. If you don\'t upload a profile picture Moodle will attempt to load a profile picture for you from Gravatar.';
$string['group'] = 'Group';
$string['groupadd'] = 'Add new group';
$string['groupaddusers'] = 'Add selected to group';
@@ -1153,7 +1140,7 @@
$string['makeafolder'] = 'Create folder';
$string['makeavailable'] = 'Make available';
$string['makeeditable'] = 'If you make \'{$a}\' editable by the web server process (eg apache) then you could edit this file directly from this page';
-$string['makethismyhome'] = 'Make this my default home page';
+$string['makethismyhome'] = 'Make this my home page';
$string['makeunavailable'] = 'Make unavailable';
$string['manageblocks'] = 'Blocks';
$string['managecategorythis'] = 'Manage this category';
@@ -1183,8 +1170,8 @@
$string['maxnumcoursesincombo'] = 'Browse {$a->numberofcourses} courses.';
$string['maxsize'] = 'Max size: {$a}';
$string['maxsizeandareasize'] = 'Maximum size for new files: {$a->size}, overall limit: {$a->areasize}';
-$string['maxsizeandattachments'] = 'Maximum size for new files: {$a->size}, maximum attachments: {$a->attachments}';
-$string['maxsizeandattachmentsandareasize'] = 'Maximum size for new files: {$a->size}, maximum attachments: {$a->attachments}, overall limit: {$a->areasize}';
+$string['maxsizeandattachments'] = 'Maximum file size: {$a->size}, maximum number of files: {$a->attachments}';
+$string['maxsizeandattachmentsandareasize'] = 'Maximum file size: {$a->size}, maximum number of files: {$a->attachments}, maximum total size: {$a->areasize}';
$string['memberincourse'] = 'People in the course';
$string['messagebody'] = 'Message body';
$string['messagedselectedusers'] = 'Selected users have been messaged and the recipient list has been reset.';
@@ -1639,9 +1626,9 @@
If you choose, you can allow your site name, country and URL to be added to the public list of Moodle Sites.
All new registrations are verified manually before they are added to the list, but once you are added you can update your registration (and your entry on the public list) at any time by resubmitting this form.
';
$string['registrationinfotitle'] = 'Registration information';
-$string['registrationno'] = 'No, I do not want to receive any email from Moodle HQ';
+$string['registrationno'] = 'No, I do not wish to receive any emails';
$string['registrationsend'] = 'Send registration information to moodle.org';
-$string['registrationyes'] = 'Yes, notify me about important news (e.g. security issues or releases) ';
+$string['registrationyes'] = 'Yes, notify me of new Moodle releases, security alerts and other important news';
$string['reject'] = 'Reject';
$string['rejectdots'] = 'Reject...';
$string['reload'] = 'Reload';
@@ -1821,6 +1808,7 @@
$string['shortsitename'] = 'Short name for site (eg single word)';
$string['show'] = 'Show';
$string['showactions'] = 'Show actions';
+$string['showadvancededitor'] = 'Advanced';
$string['showadvancedsettings'] = 'Show advanced settings';
$string['showall'] = 'Show all {$a}';
$string['showallcourses'] = 'Show all courses';
@@ -1833,7 +1821,7 @@
$string['showdescription'] = 'Display description on course page';
$string['showdescription_help'] = 'If enabled, the description above will be displayed on the course page just below the link to the activity or resource.';
$string['showgrades'] = 'Show gradebook to students';
-$string['showgrades_help'] = 'Many activities in the course allow grades to be set. This setting determines whether a student can view a list of all their grades for the course via a grades link in the course administration block.';
+$string['showgrades_help'] = 'Many activities in the course allow grades to be set. This setting determines whether a student can view a list of all their grades for the course via a grades link in the navigation drawer or block.';
$string['showingacourses'] = 'Showing all {$a} courses';
$string['showingxofycourses'] = 'Showing courses {$a->start} to {$a->end} of {$a->total} courses';
$string['showlistofcourses'] = 'Show list of courses';
@@ -1920,7 +1908,7 @@
$string['statsreport11'] = 'Most active courses';
$string['statsreport12'] = 'Most active courses (weighted)';
$string['statsreport13'] = 'Most participatory courses (enrolments)';
-$string['statsreport14'] = 'Most participatory courses (views/posts)';
+$string['statsreport14'] = 'Most participatory courses (posts/views)';
$string['statsreport2'] = 'Views (all roles)';
$string['statsreport3'] = 'Posts (all roles)';
$string['statsreport4'] = 'All activity (all roles)';
diff --git a/lang/en/my.php b/lang/en/my.php
index 216b1ab08d044..02b2a82651459 100644
--- a/lang/en/my.php
+++ b/lang/en/my.php
@@ -38,4 +38,4 @@
$string['reseteveryonesprofile'] = 'Reset profile for all users';
$string['resetpage'] = 'Reset page to default';
$string['reseterror'] = 'There was an error resetting your page';
-$string['privacy:metadata:core_my:preference:user_home_page_preference'] = 'The user home page preference configured for the Dashboard page.';
+$string['privacy:metadata:core_my:preference:user_home_page_preference'] = 'The user home page preference.';
diff --git a/lang/en/question.php b/lang/en/question.php
index 7dc290e5ef76f..8663ab9ebebe1 100644
--- a/lang/en/question.php
+++ b/lang/en/question.php
@@ -283,7 +283,7 @@
$string['questionname'] = 'Question name';
$string['questionno'] = 'Question {$a}';
$string['questionsaveerror'] = 'Errors occur during saving question - ({$a})';
-$string['questionsinuse'] = '(* Questions marked by an asterisk are already in use in some quizzes. These questions will not be deleted from these quizzes but only from the category list.)';
+$string['questionsinuse'] = '(* Questions marked with an asterisk are used somewhere, for example in a quiz. Therefore, if you proceed, these questions will not really be deleted, they will just be hidden.)';
$string['questionsmovedto'] = 'Questions still in use moved to "{$a}" in the parent course category.';
$string['questionsrescuedfrom'] = 'Questions saved from context {$a}.';
$string['questionsrescuedfrominfo'] = 'These questions (some of which may be hidden) were saved when context {$a} was deleted because they are still used by some quizzes or other activities.';
diff --git a/lang/en/rating.php b/lang/en/rating.php
index 4e03d2fa5a700..6b351266d26ac 100644
--- a/lang/en/rating.php
+++ b/lang/en/rating.php
@@ -53,7 +53,7 @@
$string['ratingtime'] = 'Restrict ratings to items with dates in this range:';
$string['ratings'] = 'Ratings';
$string['rolewarning'] = 'Roles with permission to rate';
-$string['rolewarning_help'] = 'To submit ratings users require the moodle/rating:rate capability and any module specific capabilities. Users assigned the following roles should be able to rate items. The list of roles may be amended via the permissions link in the administration block.';
+$string['rolewarning_help'] = 'To submit ratings users require the moodle/rating:rate capability and any module specific capabilities. Users assigned the following roles should be able to rate items. The list of roles may be amended via the permissions link in the actions menu or administration block, depending on the theme.';
$string['scaleselectionrequired'] = 'When selecting a ratings aggregate type you must also select to use either a scale or set a maximum points.';
$string['privacy:metadata:rating'] = 'The user-entered rating is stored alongside a mapping of the item which was rated.';
$string['privacy:metadata:rating:userid'] = 'The user who made the rating.';
diff --git a/lang/en/repository.php b/lang/en/repository.php
index be5d95fe574ea..c01d5899959f9 100644
--- a/lang/en/repository.php
+++ b/lang/en/repository.php
@@ -63,8 +63,8 @@
$string['configcacheexpire'] = 'The amount of time that file listings are cached locally (in seconds) when browsing external repositories.';
$string['configgetfiletimeout'] = 'Timeout in seconds for downloading an external file into Moodle.';
$string['configsaved'] = 'Configuration saved!';
-$string['configsyncfiletimeout'] = 'Timeout in seconds for syncronising the external file size.';
-$string['configsyncimagetimeout'] = 'Timeout in seconds for downloading an image file from external repository during syncronisation.';
+$string['configsyncfiletimeout'] = 'Timeout in seconds for synchronising the external file size.';
+$string['configsyncimagetimeout'] = 'Timeout in seconds for downloading an image file from external repository during synchronisation.';
$string['confirmdelete'] = 'Are you sure you want to delete the repository {$a}? If you choose "Continue and download", file references to external contents will be downloaded to Moodle. This could take a long time to process.';
$string['confirmdeletefile'] = 'Are you sure you want to delete this file?';
$string['confirmrenamefile'] = 'Are you sure you want to rename/move this file? There are {$a} alias/shortcut files that use this file as their source. If you proceed then those aliases will be converted to true copies.';
diff --git a/lang/en/search.php b/lang/en/search.php
index 7d791e3a738b2..20c5ddd879186 100644
--- a/lang/en/search.php
+++ b/lang/en/search.php
@@ -118,7 +118,7 @@
$string['search:section'] = 'Course sections';
$string['search:user'] = 'Users';
$string['searcharea'] = 'Search area';
-$string['searchareacategories'] = 'Seach area categories';
+$string['searchareacategories'] = 'Search area categories';
$string['searching'] = 'Searching in ...';
$string['searchnotpermitted'] = 'You are not allowed to do a search';
$string['searchsetupdescription'] = 'The following steps help you to set up Moodle global search.';
diff --git a/lang/en/timezones.php b/lang/en/timezones.php
index 01a1feaec17c9..417a4fb108b2d 100644
--- a/lang/en/timezones.php
+++ b/lang/en/timezones.php
@@ -27,7 +27,7 @@
$string['africa/accra'] = 'Africa/Accra';
$string['africa/addis_ababa'] = 'Africa/Addis_Ababa';
$string['africa/algiers'] = 'Africa/Algiers';
-$string['africa/asmera'] = 'Africa/Asmera';
+$string['africa/asmara'] = 'Africa/Asmara';
$string['africa/bamako'] = 'Africa/Bamako';
$string['africa/bangui'] = 'Africa/Bangui';
$string['africa/banjul'] = 'Africa/Banjul';
@@ -48,6 +48,7 @@
$string['africa/gaborone'] = 'Africa/Gaborone';
$string['africa/harare'] = 'Africa/Harare';
$string['africa/johannesburg'] = 'Africa/Johannesburg';
+$string['africa/juba'] = 'Africa/Juba';
$string['africa/kampala'] = 'Africa/Kampala';
$string['africa/khartoum'] = 'Africa/Khartoum';
$string['africa/kigali'] = 'Africa/Kigali';
@@ -71,32 +72,35 @@
$string['africa/ouagadougou'] = 'Africa/Ouagadougou';
$string['africa/porto-novo'] = 'Africa/Porto-Novo';
$string['africa/sao_tome'] = 'Africa/Sao_Tome';
-$string['africa/timbuktu'] = 'Africa/Timbuktu';
$string['africa/tripoli'] = 'Africa/Tripoli';
$string['africa/tunis'] = 'Africa/Tunis';
$string['africa/windhoek'] = 'Africa/Windhoek';
$string['america/adak'] = 'America/Adak';
-$string['america/anguilla'] = 'America/Anguilla';
$string['america/anchorage'] = 'America/Anchorage';
+$string['america/anguilla'] = 'America/Anguilla';
$string['america/antigua'] = 'America/Antigua';
$string['america/araguaina'] = 'America/Araguaina';
$string['america/argentina/buenos_aires'] = 'America/Argentina/Buenos_Aires';
$string['america/argentina/catamarca'] = 'America/Argentina/Catamarca';
-$string['america/argentina/comodrivadavia'] = 'America/Argentina/ComodRivadavia';
$string['america/argentina/cordoba'] = 'America/Argentina/Cordoba';
$string['america/argentina/jujuy'] = 'America/Argentina/Jujuy';
$string['america/argentina/la_rioja'] = 'America/Argentina/La_Rioja';
$string['america/argentina/mendoza'] = 'America/Argentina/Mendoza';
$string['america/argentina/rio_gallegos'] = 'America/Argentina/Rio_Gallegos';
+$string['america/argentina/salta'] = 'America/Argentina/Salta';
$string['america/argentina/san_juan'] = 'America/Argentina/San_Juan';
+$string['america/argentina/san_luis'] = 'America/Argentina/San_Luis';
$string['america/argentina/tucuman'] = 'America/Argentina/Tucuman';
$string['america/argentina/ushuaia'] = 'America/Argentina/Ushuaia';
$string['america/aruba'] = 'America/Aruba';
$string['america/asuncion'] = 'America/Asuncion';
+$string['america/atikokan'] = 'America/Atikokan';
$string['america/bahia'] = 'America/Bahia';
+$string['america/bahia_banderas'] = 'America/Bahia_Banderas';
$string['america/barbados'] = 'America/Barbados';
$string['america/belem'] = 'America/Belem';
$string['america/belize'] = 'America/Belize';
+$string['america/blanc-sablon'] = 'America/Blanc-Sablon';
$string['america/boa_vista'] = 'America/Boa_Vista';
$string['america/bogota'] = 'America/Bogota';
$string['america/boise'] = 'America/Boise';
@@ -106,7 +110,10 @@
$string['america/caracas'] = 'America/Caracas';
$string['america/cayenne'] = 'America/Cayenne';
$string['america/cayman'] = 'America/Cayman';
+$string['america/chicago'] = 'America/Chicago';
+$string['america/chihuahua'] = 'America/Chihuahua';
$string['america/costa_rica'] = 'America/Costa_Rica';
+$string['america/creston'] = 'America/Creston';
$string['america/cuiaba'] = 'America/Cuiaba';
$string['america/curacao'] = 'America/Curacao';
$string['america/danmarkshavn'] = 'America/Danmarkshavn';
@@ -118,6 +125,7 @@
$string['america/edmonton'] = 'America/Edmonton';
$string['america/eirunepe'] = 'America/Eirunepe';
$string['america/el_salvador'] = 'America/El_Salvador';
+$string['america/fort_nelson'] = 'America/Fort_Nelson';
$string['america/fortaleza'] = 'America/Fortaleza';
$string['america/glace_bay'] = 'America/Glace_Bay';
$string['america/godthab'] = 'America/Godthab';
@@ -131,40 +139,50 @@
$string['america/halifax'] = 'America/Halifax';
$string['america/havana'] = 'America/Havana';
$string['america/hermosillo'] = 'America/Hermosillo';
-$string['america/chicago'] = 'America/Chicago';
-$string['america/chihuahua'] = 'America/Chihuahua';
+$string['america/indiana/indianapolis'] = 'America/Indiana/Indianapolis';
$string['america/indiana/knox'] = 'America/Indiana/Knox';
$string['america/indiana/marengo'] = 'America/Indiana/Marengo';
-$string['america/indianapolis'] = 'America/Indianapolis';
+$string['america/indiana/petersburg'] = 'America/Indiana/Petersburg';
+$string['america/indiana/tell_city'] = 'America/Indiana/Tell_City';
$string['america/indiana/vevay'] = 'America/Indiana/Vevay';
+$string['america/indiana/vincennes'] = 'America/Indiana/Vincennes';
+$string['america/indiana/winamac'] = 'America/Indiana/Winamac';
$string['america/inuvik'] = 'America/Inuvik';
$string['america/iqaluit'] = 'America/Iqaluit';
$string['america/jamaica'] = 'America/Jamaica';
$string['america/juneau'] = 'America/Juneau';
+$string['america/kentucky/louisville'] = 'America/Kentucky/Louisville';
$string['america/kentucky/monticello'] = 'America/Kentucky/Monticello';
+$string['america/kralendijk'] = 'America/Kralendijk';
$string['america/la_paz'] = 'America/La_Paz';
$string['america/lima'] = 'America/Lima';
$string['america/los_angeles'] = 'America/Los_Angeles';
-$string['america/louisville'] = 'America/Louisville';
+$string['america/lower_princes'] = 'America/Lower_Princes';
$string['america/maceio'] = 'America/Maceio';
$string['america/managua'] = 'America/Managua';
$string['america/manaus'] = 'America/Manaus';
+$string['america/marigot'] = 'America/Marigot';
$string['america/martinique'] = 'America/Martinique';
+$string['america/matamoros'] = 'America/Matamoros';
$string['america/mazatlan'] = 'America/Mazatlan';
$string['america/menominee'] = 'America/Menominee';
$string['america/merida'] = 'America/Merida';
+$string['america/metlakatla'] = 'America/Metlakatla';
$string['america/mexico_city'] = 'America/Mexico_City';
$string['america/miquelon'] = 'America/Miquelon';
+$string['america/moncton'] = 'America/Moncton';
$string['america/monterrey'] = 'America/Monterrey';
$string['america/montevideo'] = 'America/Montevideo';
-$string['america/montreal'] = 'America/Montreal';
$string['america/montserrat'] = 'America/Montserrat';
$string['america/nassau'] = 'America/Nassau';
$string['america/new_york'] = 'America/New_York';
$string['america/nipigon'] = 'America/Nipigon';
$string['america/nome'] = 'America/Nome';
$string['america/noronha'] = 'America/Noronha';
+$string['america/north_dakota/beulah'] = 'America/North_Dakota/Beulah';
$string['america/north_dakota/center'] = 'America/North_Dakota/Center';
+$string['america/north_dakota/new_salem'] = 'America/North_Dakota/New_Salem';
+$string['america/ojinaga'] = 'America/Ojinaga';
$string['america/panama'] = 'America/Panama';
$string['america/pangnirtung'] = 'America/Pangnirtung';
$string['america/paramaribo'] = 'America/Paramaribo';
@@ -173,15 +191,20 @@
$string['america/port_of_spain'] = 'America/Port_of_Spain';
$string['america/porto_velho'] = 'America/Porto_Velho';
$string['america/puerto_rico'] = 'America/Puerto_Rico';
+$string['america/punta_arenas'] = 'America/Punta_Arenas';
$string['america/rainy_river'] = 'America/Rainy_River';
$string['america/rankin_inlet'] = 'America/Rankin_Inlet';
$string['america/recife'] = 'America/Recife';
$string['america/regina'] = 'America/Regina';
+$string['america/resolute'] = 'America/Resolute';
$string['america/rio_branco'] = 'America/Rio_Branco';
+$string['america/santarem'] = 'America/Santarem';
$string['america/santiago'] = 'America/Santiago';
$string['america/santo_domingo'] = 'America/Santo_Domingo';
$string['america/sao_paulo'] = 'America/Sao_Paulo';
$string['america/scoresbysund'] = 'America/Scoresbysund';
+$string['america/sitka'] = 'America/Sitka';
+$string['america/st_barthelemy'] = 'America/St_Barthelemy';
$string['america/st_johns'] = 'America/St_Johns';
$string['america/st_kitts'] = 'America/St_Kitts';
$string['america/st_lucia'] = 'America/St_Lucia';
@@ -202,12 +225,15 @@
$string['antarctica/casey'] = 'Antarctica/Casey';
$string['antarctica/davis'] = 'Antarctica/Davis';
$string['antarctica/dumontdurville'] = 'Antarctica/DumontDUrville';
+$string['antarctica/macquarie'] = 'Antarctica/Macquarie';
$string['antarctica/mawson'] = 'Antarctica/Mawson';
$string['antarctica/mcmurdo'] = 'Antarctica/McMurdo';
$string['antarctica/palmer'] = 'Antarctica/Palmer';
$string['antarctica/rothera'] = 'Antarctica/Rothera';
$string['antarctica/syowa'] = 'Antarctica/Syowa';
+$string['antarctica/troll'] = 'Antarctica/Troll';
$string['antarctica/vostok'] = 'Antarctica/Vostok';
+$string['arctic/longyearbyen'] = 'Arctic/Longyearbyen';
$string['asia/aden'] = 'Asia/Aden';
$string['asia/almaty'] = 'Asia/Almaty';
$string['asia/amman'] = 'Asia/Amman';
@@ -215,34 +241,39 @@
$string['asia/aqtau'] = 'Asia/Aqtau';
$string['asia/aqtobe'] = 'Asia/Aqtobe';
$string['asia/ashgabat'] = 'Asia/Ashgabat';
+$string['asia/atyrau'] = 'Asia/Atyrau';
$string['asia/baghdad'] = 'Asia/Baghdad';
$string['asia/bahrain'] = 'Asia/Bahrain';
$string['asia/baku'] = 'Asia/Baku';
$string['asia/bangkok'] = 'Asia/Bangkok';
+$string['asia/barnaul'] = 'Asia/Barnaul';
$string['asia/beirut'] = 'Asia/Beirut';
$string['asia/bishkek'] = 'Asia/Bishkek';
$string['asia/brunei'] = 'Asia/Brunei';
-$string['asia/calcutta'] = 'Asia/Calcutta';
+$string['asia/chita'] = 'Asia/Chita';
+$string['asia/choibalsan'] = 'Asia/Choibalsan';
$string['asia/colombo'] = 'Asia/Colombo';
$string['asia/damascus'] = 'Asia/Damascus';
$string['asia/dhaka'] = 'Asia/Dhaka';
$string['asia/dili'] = 'Asia/Dili';
$string['asia/dubai'] = 'Asia/Dubai';
$string['asia/dushanbe'] = 'Asia/Dushanbe';
+$string['asia/famagusta'] = 'Asia/Famagusta';
$string['asia/gaza'] = 'Asia/Gaza';
-$string['asia/harbin'] = 'Asia/Harbin';
+$string['asia/hebron'] = 'Asia/Hebron';
+$string['asia/ho_chi_minh'] = 'Asia/Ho_Chi_Minh';
$string['asia/hong_kong'] = 'Asia/Hong_Kong';
$string['asia/hovd'] = 'Asia/Hovd';
-$string['asia/choibalsan'] = 'Asia/Choibalsan';
-$string['asia/chongqing'] = 'Asia/Chongqing';
$string['asia/irkutsk'] = 'Asia/Irkutsk';
+$string['asia/jakarta'] = 'Asia/Jakarta';
$string['asia/jayapura'] = 'Asia/Jayapura';
$string['asia/jerusalem'] = 'Asia/Jerusalem';
$string['asia/kabul'] = 'Asia/Kabul';
$string['asia/kamchatka'] = 'Asia/Kamchatka';
$string['asia/karachi'] = 'Asia/Karachi';
-$string['asia/kashgar'] = 'Asia/Kashgar';
-$string['asia/katmandu'] = 'Asia/Katmandu';
+$string['asia/kathmandu'] = 'Asia/Kathmandu';
+$string['asia/khandyga'] = 'Asia/Khandyga';
+$string['asia/kolkata'] = 'Asia/Kolkata';
$string['asia/krasnoyarsk'] = 'Asia/Krasnoyarsk';
$string['asia/kuala_lumpur'] = 'Asia/Kuala_Lumpur';
$string['asia/kuching'] = 'Asia/Kuching';
@@ -253,6 +284,7 @@
$string['asia/manila'] = 'Asia/Manila';
$string['asia/muscat'] = 'Asia/Muscat';
$string['asia/nicosia'] = 'Asia/Nicosia';
+$string['asia/novokuznetsk'] = 'Asia/Novokuznetsk';
$string['asia/novosibirsk'] = 'Asia/Novosibirsk';
$string['asia/omsk'] = 'Asia/Omsk';
$string['asia/oral'] = 'Asia/Oral';
@@ -260,42 +292,47 @@
$string['asia/pontianak'] = 'Asia/Pontianak';
$string['asia/pyongyang'] = 'Asia/Pyongyang';
$string['asia/qatar'] = 'Asia/Qatar';
+$string['asia/qostanay'] = 'Asia/Qostanay';
$string['asia/qyzylorda'] = 'Asia/Qyzylorda';
-$string['asia/rangoon'] = 'Asia/Rangoon';
$string['asia/riyadh'] = 'Asia/Riyadh';
-$string['asia/saigon'] = 'Asia/Saigon';
$string['asia/sakhalin'] = 'Asia/Sakhalin';
$string['asia/samarkand'] = 'Asia/Samarkand';
$string['asia/seoul'] = 'Asia/Seoul';
$string['asia/shanghai'] = 'Asia/Shanghai';
$string['asia/singapore'] = 'Asia/Singapore';
+$string['asia/srednekolymsk'] = 'Asia/Srednekolymsk';
$string['asia/taipei'] = 'Asia/Taipei';
$string['asia/tashkent'] = 'Asia/Tashkent';
$string['asia/tbilisi'] = 'Asia/Tbilisi';
$string['asia/tehran'] = 'Asia/Tehran';
$string['asia/thimphu'] = 'Asia/Thimphu';
$string['asia/tokyo'] = 'Asia/Tokyo';
+$string['asia/tomsk'] = 'Asia/Tomsk';
$string['asia/ulaanbaatar'] = 'Asia/Ulaanbaatar';
$string['asia/urumqi'] = 'Asia/Urumqi';
+$string['asia/ust-nera'] = 'Asia/Ust-Nera';
$string['asia/vientiane'] = 'Asia/Vientiane';
$string['asia/vladivostok'] = 'Asia/Vladivostok';
$string['asia/yakutsk'] = 'Asia/Yakutsk';
+$string['asia/yangon'] = 'Asia/Yangon';
$string['asia/yekaterinburg'] = 'Asia/Yekaterinburg';
$string['asia/yerevan'] = 'Asia/Yerevan';
$string['atlantic/azores'] = 'Atlantic/Azores';
$string['atlantic/bermuda'] = 'Atlantic/Bermuda';
$string['atlantic/canary'] = 'Atlantic/Canary';
$string['atlantic/cape_verde'] = 'Atlantic/Cape_Verde';
-$string['atlantic/faeroe'] = 'Atlantic/Faeroe';
+$string['atlantic/faroe'] = 'Atlantic/Faroe';
$string['atlantic/madeira'] = 'Atlantic/Madeira';
$string['atlantic/reykjavik'] = 'Atlantic/Reykjavik';
$string['atlantic/south_georgia'] = 'Atlantic/South_Georgia';
-$string['atlantic/stanley'] = 'Atlantic/Stanley';
$string['atlantic/st_helena'] = 'Atlantic/St_Helena';
+$string['atlantic/stanley'] = 'Atlantic/Stanley';
$string['australia/adelaide'] = 'Australia/Adelaide';
$string['australia/brisbane'] = 'Australia/Brisbane';
$string['australia/broken_hill'] = 'Australia/Broken_Hill';
+$string['australia/currie'] = 'Australia/Currie';
$string['australia/darwin'] = 'Australia/Darwin';
+$string['australia/eucla'] = 'Australia/Eucla';
$string['australia/hobart'] = 'Australia/Hobart';
$string['australia/lindeman'] = 'Australia/Lindeman';
$string['australia/lord_howe'] = 'Australia/Lord_Howe';
@@ -304,51 +341,69 @@
$string['australia/sydney'] = 'Australia/Sydney';
$string['europe/amsterdam'] = 'Europe/Amsterdam';
$string['europe/andorra'] = 'Europe/Andorra';
+$string['europe/astrakhan'] = 'Europe/Astrakhan';
$string['europe/athens'] = 'Europe/Athens';
-$string['europe/belfast'] = 'Europe/Belfast';
$string['europe/belgrade'] = 'Europe/Belgrade';
$string['europe/berlin'] = 'Europe/Berlin';
+$string['europe/bratislava'] = 'Europe/Bratislava';
$string['europe/brussels'] = 'Europe/Brussels';
-$string['europe/budapest'] = 'Europe/Budapest';
$string['europe/bucharest'] = 'Europe/Bucharest';
+$string['europe/budapest'] = 'Europe/Budapest';
+$string['europe/busingen'] = 'Europe/Busingen';
+$string['europe/chisinau'] = 'Europe/Chisinau';
$string['europe/copenhagen'] = 'Europe/Copenhagen';
$string['europe/dublin'] = 'Europe/Dublin';
$string['europe/gibraltar'] = 'Europe/Gibraltar';
+$string['europe/guernsey'] = 'Europe/Guernsey';
$string['europe/helsinki'] = 'Europe/Helsinki';
-$string['europe/chisinau'] = 'Europe/Chisinau';
+$string['europe/isle_of_man'] = 'Europe/Isle_of_Man';
$string['europe/istanbul'] = 'Europe/Istanbul';
+$string['europe/jersey'] = 'Europe/Jersey';
$string['europe/kaliningrad'] = 'Europe/Kaliningrad';
$string['europe/kiev'] = 'Europe/Kiev';
+$string['europe/kirov'] = 'Europe/Kirov';
$string['europe/lisbon'] = 'Europe/Lisbon';
+$string['europe/ljubljana'] = 'Europe/Ljubljana';
$string['europe/london'] = 'Europe/London';
$string['europe/luxembourg'] = 'Europe/Luxembourg';
$string['europe/madrid'] = 'Europe/Madrid';
$string['europe/malta'] = 'Europe/Malta';
+$string['europe/mariehamn'] = 'Europe/Mariehamn';
$string['europe/minsk'] = 'Europe/Minsk';
$string['europe/monaco'] = 'Europe/Monaco';
$string['europe/moscow'] = 'Europe/Moscow';
$string['europe/oslo'] = 'Europe/Oslo';
$string['europe/paris'] = 'Europe/Paris';
+$string['europe/podgorica'] = 'Europe/Podgorica';
$string['europe/prague'] = 'Europe/Prague';
$string['europe/riga'] = 'Europe/Riga';
$string['europe/rome'] = 'Europe/Rome';
$string['europe/samara'] = 'Europe/Samara';
+$string['europe/san_marino'] = 'Europe/San_Marino';
+$string['europe/sarajevo'] = 'Europe/Sarajevo';
+$string['europe/saratov'] = 'Europe/Saratov';
$string['europe/simferopol'] = 'Europe/Simferopol';
+$string['europe/skopje'] = 'Europe/Skopje';
$string['europe/sofia'] = 'Europe/Sofia';
$string['europe/stockholm'] = 'Europe/Stockholm';
$string['europe/tallinn'] = 'Europe/Tallinn';
$string['europe/tirane'] = 'Europe/Tirane';
+$string['europe/ulyanovsk'] = 'Europe/Ulyanovsk';
$string['europe/uzhgorod'] = 'Europe/Uzhgorod';
$string['europe/vaduz'] = 'Europe/Vaduz';
+$string['europe/vatican'] = 'Europe/Vatican';
$string['europe/vienna'] = 'Europe/Vienna';
$string['europe/vilnius'] = 'Europe/Vilnius';
+$string['europe/volgograd'] = 'Europe/Volgograd';
$string['europe/warsaw'] = 'Europe/Warsaw';
+$string['europe/zagreb'] = 'Europe/Zagreb';
$string['europe/zaporozhye'] = 'Europe/Zaporozhye';
$string['europe/zurich'] = 'Europe/Zurich';
$string['indian/antananarivo'] = 'Indian/Antananarivo';
-$string['indian/comoro'] = 'Indian/Comoro';
$string['indian/chagos'] = 'Indian/Chagos';
$string['indian/christmas'] = 'Indian/Christmas';
+$string['indian/cocos'] = 'Indian/Cocos';
+$string['indian/comoro'] = 'Indian/Comoro';
$string['indian/kerguelen'] = 'Indian/Kerguelen';
$string['indian/mahe'] = 'Indian/Mahe';
$string['indian/maldives'] = 'Indian/Maldives';
@@ -357,6 +412,9 @@
$string['indian/reunion'] = 'Indian/Reunion';
$string['pacific/apia'] = 'Pacific/Apia';
$string['pacific/auckland'] = 'Pacific/Auckland';
+$string['pacific/bougainville'] = 'Pacific/Bougainville';
+$string['pacific/chatham'] = 'Pacific/Chatham';
+$string['pacific/chuuk'] = 'Pacific/Chuuk';
$string['pacific/easter'] = 'Pacific/Easter';
$string['pacific/efate'] = 'Pacific/Efate';
$string['pacific/enderbury'] = 'Pacific/Enderbury';
@@ -368,7 +426,6 @@
$string['pacific/guadalcanal'] = 'Pacific/Guadalcanal';
$string['pacific/guam'] = 'Pacific/Guam';
$string['pacific/honolulu'] = 'Pacific/Honolulu';
-$string['pacific/chatham'] = 'Pacific/Chatham';
$string['pacific/kiritimati'] = 'Pacific/Kiritimati';
$string['pacific/kosrae'] = 'Pacific/Kosrae';
$string['pacific/kwajalein'] = 'Pacific/Kwajalein';
@@ -382,14 +439,33 @@
$string['pacific/pago_pago'] = 'Pacific/Pago_Pago';
$string['pacific/palau'] = 'Pacific/Palau';
$string['pacific/pitcairn'] = 'Pacific/Pitcairn';
-$string['pacific/ponape'] = 'Pacific/Ponape';
+$string['pacific/pohnpei'] = 'Pacific/Pohnpei';
$string['pacific/port_moresby'] = 'Pacific/Port_Moresby';
$string['pacific/rarotonga'] = 'Pacific/Rarotonga';
$string['pacific/saipan'] = 'Pacific/Saipan';
$string['pacific/tahiti'] = 'Pacific/Tahiti';
$string['pacific/tarawa'] = 'Pacific/Tarawa';
$string['pacific/tongatapu'] = 'Pacific/Tongatapu';
-$string['pacific/truk'] = 'Pacific/Truk';
$string['pacific/wake'] = 'Pacific/Wake';
$string['pacific/wallis'] = 'Pacific/Wallis';
+$string['utc'] = 'UTC';
+// The following identifiers have been previous removed from TimeDateZone::listIdentifiers and are no longer used.
+// Deprecated since Moodle 3.9.
+$string['africa/asmera'] = 'Africa/Asmera';
+$string['africa/timbuktu'] = 'Africa/Timbuktu';
+$string['america/argentina/comodrivadavia'] = 'America/Argentina/ComodRivadavia';
+$string['america/indianapolis'] = 'America/Indianapolis';
+$string['america/louisville'] = 'America/Louisville';
+$string['america/montreal'] = 'America/Montreal';
+$string['asia/calcutta'] = 'Asia/Calcutta';
+$string['asia/chongqing'] = 'Asia/Chongqing';
+$string['asia/harbin'] = 'Asia/Harbin';
+$string['asia/kashgar'] = 'Asia/Kashgar';
+$string['asia/katmandu'] = 'Asia/Katmandu';
+$string['asia/rangoon'] = 'Asia/Rangoon';
+$string['asia/saigon'] = 'Asia/Saigon';
+$string['atlantic/faeroe'] = 'Atlantic/Faeroe';
+$string['europe/belfast'] = 'Europe/Belfast';
+$string['pacific/ponape'] = 'Pacific/Ponape';
+$string['pacific/truk'] = 'Pacific/Truk';
$string['pacific/yap'] = 'Pacific/Yap';
diff --git a/lang/en/user.php b/lang/en/user.php
index 56777bb11e1aa..aefc750d36740 100644
--- a/lang/en/user.php
+++ b/lang/en/user.php
@@ -47,7 +47,7 @@
$string['privacy:metadata:devicename'] = 'The device name, occam or iPhone etc..';
$string['privacy:metadata:devicetablesummary'] = 'This table stores user\'s mobile devices information in order to send PUSH notifications';
$string['privacy:metadata:email'] = 'An email address for contact.';
-$string['privacy:metadata:emailstop'] = 'A preference to stop email being sent to the user.';
+$string['privacy:metadata:emailstop'] = 'A preference to disable notifications from being sent to the user.';
$string['privacy:metadata:fieldid'] = 'The ID relating to the custom user field.';
$string['privacy:metadata:filelink'] = 'There are multiple different files for the user stored in the files table.';
$string['privacy:metadata:firstaccess'] = 'The time that this user first accessed the site.';
diff --git a/lib/accesslib.php b/lib/accesslib.php
index e80ba19c445f0..b3f9a41356ccd 100644
--- a/lib/accesslib.php
+++ b/lib/accesslib.php
@@ -5254,6 +5254,15 @@ public function set_locked(bool $locked) {
$this->_locked = $locked;
$DB->set_field('context', 'locked', (int) $locked, ['id' => $this->id]);
$this->mark_dirty();
+
+ if ($locked) {
+ $eventname = '\\core\\event\\context_locked';
+ } else {
+ $eventname = '\\core\\event\\context_unlocked';
+ }
+ $event = $eventname::create(['context' => $this, 'objectid' => $this->id]);
+ $event->trigger();
+
self::reset_caches();
return $this;
diff --git a/lib/adminlib.php b/lib/adminlib.php
index 07f66e4aa9c2e..ef32223ccfd26 100644
--- a/lib/adminlib.php
+++ b/lib/adminlib.php
@@ -2574,6 +2574,19 @@ public function output_html($data, $query='') {
$editor->use_editor($this->get_id(), array('noclean'=>true));
return parent::output_html($data, $query);
}
+
+ /**
+ * Checks if data has empty html.
+ *
+ * @param string $data
+ * @return string Empty when no errors.
+ */
+ public function write_setting($data) {
+ if (trim(html_to_text($data)) === '') {
+ $data = '';
+ }
+ return parent::write_setting($data);
+ }
}
@@ -8382,10 +8395,12 @@ function admin_get_root($reload=false, $requirefulltree=true) {
* @return array $settingsoutput The names and values of the changed settings
*/
function admin_apply_default_settings($node=null, $unconditional=true, $admindefaultsettings=array(), $settingsoutput=array()) {
+ $counter = 0;
if (is_null($node)) {
core_plugin_manager::reset_caches();
$node = admin_get_root(true, true);
+ $counter = count($settingsoutput);
}
if ($node instanceof admin_category) {
@@ -8398,7 +8413,7 @@ function admin_apply_default_settings($node=null, $unconditional=true, $admindef
} else if ($node instanceof admin_settingpage) {
foreach ($node->settings as $setting) {
- if (!$unconditional and !is_null($setting->get_setting())) {
+ if (!$unconditional && !is_null($setting->get_setting())) {
// Do not override existing defaults.
continue;
}
@@ -8424,7 +8439,7 @@ function admin_apply_default_settings($node=null, $unconditional=true, $admindef
}
// Call this function recursively until all settings are processed.
- if (($node instanceof admin_root) && (!empty($admindefaultsettings))) {
+ if (($node instanceof admin_root) && ($counter != count($settingsoutput))) {
$settingsoutput = admin_apply_default_settings(null, $unconditional, $admindefaultsettings, $settingsoutput);
}
// Just in case somebody modifies the list of active plugins directly.
diff --git a/lib/adodb/drivers/adodb-mssql.inc.php b/lib/adodb/drivers/adodb-mssql.inc.php
index 068dffce0d956..3e6de38f7cf72 100644
--- a/lib/adodb/drivers/adodb-mssql.inc.php
+++ b/lib/adodb/drivers/adodb-mssql.inc.php
@@ -680,7 +680,9 @@ function Concat()
$arr = $args;
}
- array_walk($arr, create_function('&$v', '$v = "CAST(" . $v . " AS VARCHAR(255))";'));
+ array_walk($arr, function(&$v) {
+ $v = "CAST(" . $v . " AS VARCHAR(255))";
+ });
$s = implode('+',$arr);
if (sizeof($arr) > 0) return "$s";
diff --git a/lib/adodb/drivers/adodb-mssqlnative.inc.php b/lib/adodb/drivers/adodb-mssqlnative.inc.php
index 23eb2c03d4cec..e70219b19775e 100644
--- a/lib/adodb/drivers/adodb-mssqlnative.inc.php
+++ b/lib/adodb/drivers/adodb-mssqlnative.inc.php
@@ -527,7 +527,9 @@ function Concat()
$arr = $args;
}
- array_walk($arr, create_function('&$v', '$v = "CAST(" . $v . " AS VARCHAR(255))";'));
+ array_walk($arr, function(&$v) {
+ $v = "CAST(" . $v . " AS VARCHAR(255))";
+ });
$s = implode('+',$arr);
if (sizeof($arr) > 0) return "$s";
diff --git a/lib/adodb/drivers/adodb-postgres8.inc.php b/lib/adodb/drivers/adodb-postgres8.inc.php
index 54b14abbce0a2..1c77796d7d712 100644
--- a/lib/adodb/drivers/adodb-postgres8.inc.php
+++ b/lib/adodb/drivers/adodb-postgres8.inc.php
@@ -20,6 +20,12 @@ class ADODB_postgres8 extends ADODB_postgres7
{
var $databaseType = 'postgres8';
+ // From PostgreSQL 8.0 onwards, the adsrc column used in earlier versions to
+ // retrieve the default value is obsolete and should not be used (see #562).
+ var $metaDefaultsSQL = "SELECT d.adnum as num, pg_get_expr(d.adbin, d.adrelid) as def
+ FROM pg_attrdef d, pg_class c
+ WHERE d.adrelid=c.oid AND c.relname='%s'
+ ORDER BY d.adnum";
/**
* Retrieve last inserted ID
diff --git a/lib/adodb/drivers/adodb-text.inc.php b/lib/adodb/drivers/adodb-text.inc.php
index 8844d20e14f91..56a523934019e 100644
--- a/lib/adodb/drivers/adodb-text.inc.php
+++ b/lib/adodb/drivers/adodb-text.inc.php
@@ -260,7 +260,7 @@ function _query($sql,$input_arr,$eval=false)
$projnames = array($n);
reset($where_arr);
- while (list($k_a,$a) = each($where_arr)) {
+ foreach ($where_arr as $k_a => $a) {
if ($i == 0 && $this->_skiprow1) {
$projarray[] = array($n);
continue;
diff --git a/lib/adodb/readme_moodle.txt b/lib/adodb/readme_moodle.txt
index 00ff24052c0ac..8d900f5d56231 100644
--- a/lib/adodb/readme_moodle.txt
+++ b/lib/adodb/readme_moodle.txt
@@ -32,5 +32,7 @@ Our changes:
Check if fixed upstream during the next upgrade and remove this note. (8638b3f1441d4b928)
* MDL-58546 replaced each() with foreach for PHP 7.2 compatibility.
pull request upstream: https://github.com/ADOdb/ADOdb/pull/373
+ * MDL-65920 solved PHP 7.2 deprecations; create_function() and each().
+ * MDL-67414 Fix to make the library PostgreSQL 12.x compliant (upstream: a4876f100602c2ce4).
-skodak, iarenaza, moodler, stronk7, abgreeve, lameze, ankitagarwal, marinaglancy
+skodak, iarenaza, moodler, stronk7, abgreeve, lameze, ankitagarwal, marinaglancy, matteo
diff --git a/lib/amd/build/form-autocomplete.min.js b/lib/amd/build/form-autocomplete.min.js
index 0ad553d2862b0..626ef92363016 100644
--- a/lib/amd/build/form-autocomplete.min.js
+++ b/lib/amd/build/form-autocomplete.min.js
@@ -1 +1 @@
-define(["jquery","core/log","core/str","core/templates","core/notification","core/loadingicon"],function(a,b,c,d,e,f){var g={DOWN:40,ENTER:13,SPACE:32,ESCAPE:27,COMMA:44,UP:38},h=a.now(),i=function(b,c){var d=a(document.getElementById(c.selectionId)),e=d.children("[aria-selected=true]").length;for(b%=e;b<0;)b+=e;var f=a(d.children("[aria-selected=true]").get(b)),g=c.selectionId+"-"+b;return d.children().attr("data-active-selection",!1).attr("id",""),f.attr("data-active-selection",!0).attr("id",g),d.attr("aria-activedescendant",g),a.Deferred().resolve()},j=function(b,c,f){var g="form-autocomplete-updateSelectionList-"+c.inputId;M.util.js_pending(g);var h=[],j=a(document.getElementById(c.selectionId)),k=j.attr("aria-activedescendant"),l=!1;k&&(l=a(document.getElementById(k)).attr("data-value")),f.children("option").each(function(b,c){if(a(c).prop("selected")){var d;d=a(c).data("html")?a(c).data("html"):a(c).html(),h.push({label:d,value:a(c).attr("value")})}});var m=a.extend({items:h},b,c);return d.render("core/form_autocomplete_selection",m).then(function(b,e){return d.replaceNodeContents(j,b,e),l!==!1&&j.children("[aria-selected=true]").each(function(b,d){a(d).attr("data-value")===l&&i(b,c)}),l}).then(function(){return M.util.js_complete(g)})["catch"](e.exception)},k=function(a){"undefined"!=typeof M.core_formchangechecker&&M.core_formchangechecker.set_form_changed(),a.change()},l=function(b,c,d,e){var f=a(d).attr("data-value");return b.multiple&&e.children("option").each(function(b,c){a(c).attr("value")==f&&(a(c).prop("selected",!1),a(c).attr("data-iscustom")&&a(c).remove())}),j(b,c,e).then(function(){k(e)})},m=function(b,c){var d=a(document.getElementById(c.inputId)),e=a(document.getElementById(c.suggestionsId)),f=e.children("[aria-hidden=false]").length;for(b%=f;b<0;)b+=f;var g=a(e.children("[aria-hidden=false]").get(b)),h=a(e.children("[role=option]")).index(g),i=c.suggestionsId+"-"+h;e.children().attr("aria-selected",!1).attr("id",""),g.attr("aria-selected",!0).attr("id",i),d.attr("aria-activedescendant",i);var j=g.offset().top-e.offset().top+e.scrollTop()-e.height()/2;return e.animate({scrollTop:j},100).promise()},n=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children("[aria-hidden=false]").index(d);return m(e+1,b)},o=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection=true]");if(!d)return i(0,b);var e=c.children("[aria-selected=true]").index(d);return i(e-1,b)},p=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection=true]"),e=0;return d?(e=c.children("[aria-selected=true]").index(d),e+=1):e=0,i(e,b)},q=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children("[aria-hidden=false]").index(d);return m(e-1,b)},r=function(b){var c=a(document.getElementById(b.inputId)),d=a(document.getElementById(b.suggestionsId));return c.attr("aria-expanded",!1).attr("aria-activedescendant",b.selectionId),d.hide().attr("aria-hidden",!0),a.Deferred().resolve()},s=function(b,f,g,h){var i="form-autocomplete-updateSuggestions-"+f.inputId;M.util.js_pending(i);var j=a(document.getElementById(f.inputId)),k=a(document.getElementById(f.suggestionsId)),l=!1,n=[];h.children("option").each(function(b,c){a(c).prop("selected")!==!0&&(n[n.length]={label:c.innerHTML,value:a(c).attr("value")})});var o=f.caseSensitive?g:g.toLocaleLowerCase(),p=a.extend({options:n},b,f),q=d.render("core/form_autocomplete_suggestions",p).then(function(e,g){return d.replaceNode(k,e,g),k=a(document.getElementById(f.suggestionsId)),k.show().attr("aria-hidden",!1),k.children().each(function(c,d){d=a(d),b.caseSensitive&&d.text().indexOf(o)>-1||!b.caseSensitive&&d.text().toLocaleLowerCase().indexOf(o)>-1?(d.show().attr("aria-hidden",!1),l=!0):d.hide().attr("aria-hidden",!0)}),j.attr("aria-expanded",!0),h.attr("data-notice")?k.html(h.attr("data-notice")):l?b.tags||m(0,f):c.get_string("nosuggestions","form").done(function(a){k.html(a)}),k}).then(function(){return M.util.js_complete(i)})["catch"](e.exception);return q},t=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=e.val(),g=f.split(","),h=!1;return a.each(g,function(c,e){if(e=e.trim(),""!==e&&(b.multiple||d.children("option").prop("selected",!1),d.children("option").each(function(b,c){a(c).attr("value")==e&&(h=!0,a(c).prop("selected",!0))}),!h)){var f=a("