Skip to content
Browse files

Merge branch 'MOODLE_25_STABLE' into install_25_STABLE

  • Loading branch information...
2 parents ce1a153 + d883550 commit ce31fccf0e8425fa7254b4a3b440c9856bced749 AMOS bot committed Sep 6, 2013
Showing with 862 additions and 294 deletions.
  1. +3 −1 admin/renderer.php
  2. +3 −1 admin/repository.php
  3. +3 −3 admin/tool/behat/renderer.php
  4. +2 −2 admin/tool/behat/tests/behat/basic_actions.feature
  5. +2 −2 admin/tool/langimport/lang/en/tool_langimport.php
  6. +28 −14 admin/tool/xmldb/lang/en/tool_xmldb.php
  7. +4 −3 backup/util/ui/tests/behat/backup_courses.feature
  8. +48 −3 badges/external.php
  9. +3 −0 badges/mybackpack.php
  10. +85 −14 badges/renderer.php
  11. +2 −2 blocks/course_list/lang/en/block_course_list.php
  12. +17 −17 blocks/navigation/tests/behat/view_my_courses.feature
  13. +12 −6 calendar/lib.php
  14. +1 −1 calendar/managesubscriptions.php
  15. +4 −2 calendar/renderer.php
  16. +4 −4 course/tests/behat/course_controls.feature
  17. +1 −0 enrol/ldap/lang/en/enrol_ldap.php
  18. +6 −0 enrol/ldap/lib.php
  19. +1 −1 error/index.php
  20. +5 −5 files/renderer.php
  21. +1 −1 grade/export/lib.php
  22. +8 −8 lang/en/admin.php
  23. +7 −1 lang/en/badges.php
  24. +1 −0 lang/en/cache.php
  25. +1 −1 lang/en/completion.php
  26. +1 −1 lang/en/error.php
  27. +1 −1 lang/en/install.php
  28. +1 −1 lang/en/mathslib.php
  29. +1 −0 lang/en/moodle.php
  30. +1 −1 lang/en/repository.php
  31. +14 −1 lib/badgeslib.php
  32. +6 −14 lib/behat/behat_base.php
  33. +0 −28 lib/behat/classes/behat_command.php
  34. +161 −0 lib/behat/classes/behat_selectors.php
  35. +1 −1 lib/blocklib.php
  36. +3 −0 lib/configonlylib.php
  37. +6 −0 lib/db/caches.php
  38. +1 −0 lib/dml/mssql_native_moodle_database.php
  39. +1 −0 lib/dml/sqlsrv_native_moodle_database.php
  40. +7 −0 lib/editor/tinymce/module.js
  41. +5 −3 lib/ldaplib.php
  42. +3 −2 lib/modinfolib.php
  43. +2 −0 lib/moodlelib.php
  44. +10 −0 lib/outputrenderers.php
  45. +6 −0 lib/tests/behat/behat_hooks.php
  46. +1 −1 lib/tests/configonlylib_test.php
  47. +55 −0 lib/tests/modinfolib_test.php
  48. +1 −1 lib/tests/moodlelib_test.php
  49. +2 −0 lib/upgrade.txt
  50. +1 −1 login/change_password.php
  51. +4 −0 mod/assign/backup/moodle2/restore_assign_stepslib.php
  52. +6 −5 mod/assign/locallib.php
  53. +8 −1 mod/assignment/backup/moodle1/lib.php
  54. +20 −0 mod/assignment/backup/moodle2/restore_assignment_stepslib.php
  55. +1 −0 mod/assignment/lang/en/assignment.php
  56. +6 −1 mod/assignment/lib.php
  57. +6 −2 mod/assignment/mod_form.php
  58. +5 −1 mod/assignment/view.php
  59. +1 −1 mod/feedback/lang/en/feedback.php
  60. +6 −6 mod/forum/lang/en/forum.php
  61. +3 −3 mod/forum/tests/behat/track_read_posts.feature
  62. +1 −1 mod/lesson/lang/en/lesson.php
  63. +1 −1 mod/lti/lang/en/lti.php
  64. +1 −25 portfolio/googledocs/db/upgrade.php
  65. +53 −0 portfolio/googledocs/db/upgradelib.php
  66. +1 −25 portfolio/picasa/db/upgrade.php
  67. +53 −0 portfolio/picasa/db/upgradelib.php
  68. +1 −0 question/engine/lib.php
  69. +1 −1 report/security/lang/en/report_security.php
  70. +8 −3 repository/coursefiles/lib.php
  71. +7 −2 repository/filepicker.js
  72. +1 −25 repository/googledocs/db/upgrade.php
  73. +53 −0 repository/googledocs/db/upgradelib.php
  74. +3 −10 repository/lib.php
  75. +1 −25 repository/picasa/db/upgrade.php
  76. +53 −0 repository/picasa/db/upgradelib.php
  77. +4 −2 repository/tests/behat/behat_filepicker.php
  78. +1 −0 theme/base/style/core.css
  79. +5 −0 theme/bootstrapbase/less/moodle/core.less
  80. +1 −1 theme/bootstrapbase/style/moodle.css
  81. +1 −2 user/messageselect.php
  82. +1 −1 user/profile/field/menu/lang/en/profilefield_menu.php
  83. +2 −2 version.php
View
4 admin/renderer.php
@@ -1001,9 +1001,11 @@ protected function required_column(plugininfo_base $plugin, plugin_manager $plug
} else {
$str = 'otherplugin';
}
+ $componenturl = new moodle_url('https://moodle.org/plugins/view.php?plugin='.$component);
+ $componenturl = html_writer::tag('a', $component, array('href' => $componenturl->out()));
$requires[] = html_writer::tag('li',
get_string($str, 'core_plugin',
- array('component' => $component, 'version' => $requiredversion)),
+ array('component' => $componenturl, 'version' => $requiredversion)),
array('class' => $class));
}
View
4 admin/repository.php
@@ -143,8 +143,10 @@ function repository_action_url($repository) {
$success = $repositorytype->update_options($settings);
} else {
$type = new repository_type($plugin, (array)$fromform, $visible);
- $type->create();
$success = true;
+ if (!$repoid = $type->create()) {
+ $success = false;
+ }
$data = data_submitted();
}
if ($success) {
View
6 admin/tool/behat/renderer.php
@@ -25,7 +25,7 @@
defined('MOODLE_INTERNAL') || die();
global $CFG;
-require_once($CFG->libdir . '/behat/classes/behat_command.php');
+require_once($CFG->libdir . '/behat/classes/behat_selectors.php');
/**
* Renderer for behat tool web features
@@ -92,15 +92,15 @@ public function render_stepsdefinitions($stepsdefinitions, $form) {
// Replace text selector type arguments with a user-friendly select.
$stepsdefinitions = preg_replace_callback('/(TEXT_SELECTOR\d?_STRING)/',
function ($matches) {
- return html_writer::select(behat_command::$allowedtextselectors, uniqid());
+ return html_writer::select(behat_selectors::get_allowed_text_selectors(), uniqid());
},
$stepsdefinitions
);
// Replace selector type arguments with a user-friendly select.
$stepsdefinitions = preg_replace_callback('/(SELECTOR\d?_STRING)/',
function ($matches) {
- return html_writer::select(behat_command::$allowedselectors, uniqid());
+ return html_writer::select(behat_selectors::get_allowed_selectors(), uniqid());
},
$stepsdefinitions
);
View
4 admin/tool/behat/tests/behat/basic_actions.feature
@@ -35,7 +35,7 @@ Feature: Page contents assertions
| Course 1 | C1 | 0 |
And I log in as "admin"
And I follow "Course 1"
- When I click on "Move this to the dock" "button" in the ".block_settings" "css_element"
+ When I click on "Move this to the dock" "button" in the "Administration" "block"
Then I should not see "Question bank"
And I click on "//div[@id='dock']/descendant::h2[normalize-space(.)='Administration']" "xpath_element"
@@ -45,5 +45,5 @@ Feature: Page contents assertions
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And I log in as "admin"
- When I click on "Move this to the dock" "button" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' block_settings ')]" "xpath_element"
+ When I click on "Move this to the dock" "button" in the "Administration" "block"
Then I should not see "Turn editing on"
View
4 admin/tool/langimport/lang/en/tool_langimport.php
@@ -23,7 +23,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-$string['install'] = 'Install selected language pack';
+$string['install'] = 'Install selected language pack(s)';
$string['installedlangs'] = 'Installed language packs';
$string['langimport'] = 'Language import utility';
$string['langimportdisabled'] = 'Language import feature has been disabled. You have to update your language packs manually at the file-system level. Do not forget to purge string caches after you do so.';
@@ -38,7 +38,7 @@
$string['pluginname'] = 'Language packs';
$string['purgestringcaches'] = 'Purge string caches';
$string['remotelangnotavailable'] = 'Because Moodle cannot connect to download.moodle.org, it is not possible for language packs to be installed automatically. Please download the appropriate ZIP file(s) from <a href="http://download.moodle.org/langpack/">download.moodle.org/langpack</a>, copy them to your {$a} directory and unzip them manually.';
-$string['uninstall'] = 'Uninstall selected language pack';
+$string['uninstall'] = 'Uninstall selected language pack(s)';
$string['uninstallconfirm'] = 'You are about to completely uninstall language pack {$a}, are you sure?';
$string['updatelangs'] = 'Update all installed language packs';
View
42 admin/tool/xmldb/lang/en/tool_xmldb.php
@@ -33,24 +33,38 @@
$string['confirmdeletekey'] = 'Are you absolutely sure that you want to delete the key:';
$string['confirmdeletetable'] = 'Are you absolutely sure that you want to delete the table:';
$string['confirmdeletexmlfile'] = 'Are you absolutely sure that you want to delete the file:';
-$string['confirmcheckbigints'] = 'This functionality will search for <a href="http://tracker.moodle.org/browse/MDL-11038">potential wrong integer fields</a> in your Moodle server, generating (but not executing!) automatically the needed SQL statements to have all the integers in your DB properly defined.<br /><br />
-Once generated you can copy such statements and execute them safely with your favourite SQL interface (don\'t forget to backup your data before doing that).<br /><br />
-It\'s highly recommended to be running the latest (+ version) available of your Moodle release (1.8, 1.9, 2.x ...) before executing the search of wrong integers.<br /><br />
+$string['confirmcheckbigints'] = 'This functionality will search for <a href="http://tracker.moodle.org/browse/MDL-11038">potential wrong integer fields</a> in your Moodle server, generating (but not executing!) automatically the needed SQL statements to have all the integers in your DB properly defined.
+
+Once generated you can copy such statements and execute them safely with your favourite SQL interface (don\'t forget to backup your data before doing that).
+
+It\'s highly recommended to be running the latest (+ version) available of your Moodle release before executing the search of wrong integers.
+
This functionality doesn\'t perform any action against the DB (just reads from it), so can be safely executed at any moment.';
-$string['confirmcheckdefaults'] = 'This functionality will search for inconsistent default values in your Moodle server, generating (but not executing!) the needed SQL statements to have all the default values properly defined.<br /><br />
-Once generated you can copy such statements and execute them safely with your favourite SQL interface (don\'t forget to backup your data before doing that).<br /><br />
-It\'s highly recommended to be running the latest (+ version) available of your Moodle release (1.8, 1.9, 2.x ...) before executing the search of inconsistent default values.<br /><br />
+$string['confirmcheckdefaults'] = 'This functionality will search for inconsistent default values in your Moodle server, generating (but not executing!) the needed SQL statements to have all the default values properly defined.
+
+Once generated you can copy such statements and execute them safely with your favourite SQL interface (don\'t forget to backup your data before doing that).
+
+It\'s highly recommended to be running the latest (+ version) available of your Moodle release before executing the search of inconsistent default values.
+
This functionality doesn\'t perform any action against the DB (just reads from it), so can be safely executed at any moment.';
-$string['confirmcheckforeignkeys'] = 'This functionality will search for potential violations of the foreign keys defined in the install.xml definitions. (Moodle does not currently generate actual foreign key constraints in the database, which is why invalid data may be present.)<br /><br />
-It\'s highly recommended to be running the latest (+ version) available of your Moodle release (1.8, 1.9, 2.x ...) before executing the search of missing indexes.<br /><br />
+$string['confirmcheckforeignkeys'] = 'This functionality will search for potential violations of the foreign keys defined in the install.xml definitions. (Moodle does not currently generate actual foreign key constraints in the database, which is why invalid data may be present.)
+
+It\'s highly recommended to be running the latest (+ version) available of your Moodle release before executing the search of missing indexes.
+
This functionality doesn\'t perform any action against the DB (just reads from it), so can be safely executed at any moment.';
-$string['confirmcheckindexes'] = 'This functionality will search for potential missing indexes in your Moodle server, generating (but not executing!) automatically the needed SQL statements to keep everything updated.<br /><br />
-Once generated you can copy such statements and execute them safely with your favourite SQL interface (don\'t forget to backup your data before doing that).<br /><br />
-It\'s highly recommended to be running the latest (+ version) available of your Moodle release (1.8, 1.9, 2.x ...) before executing the search of missing indexes.<br /><br />
+$string['confirmcheckindexes'] = 'This functionality will search for potential missing indexes in your Moodle server, generating (but not executing!) automatically the needed SQL statements to keep everything updated.
+
+Once generated you can copy such statements and execute them safely with your favourite SQL interface (don\'t forget to backup your data before doing that).
+
+It\'s highly recommended to be running the latest (+ version) available of your Moodle release before executing the search of missing indexes.
+
This functionality doesn\'t perform any action against the DB (just reads from it), so can be safely executed at any moment.';
-$string['confirmcheckoraclesemantics'] = 'This functionality will search for <a href="http://tracker.moodle.org/browse/MDL-29322">Oracle varchar2 columns using BYTE semantics</a> in your Moodle server, generating (but not executing!) automatically the needed SQL statements to have all the columns converted to use CHAR semantics instead (better for cross-db compatibility and increased contents max. length).<br /><br />
-Once generated you can copy such statements and execute them safely with your favourite SQL interface (don\'t forget to backup your data before doing that).<br /><br />
-It\'s highly recommended to be running the latest (+ version) available of your Moodle release (2.2, 2.3, 2.x ...) before executing the search of BYTE semantics.<br /><br />
+$string['confirmcheckoraclesemantics'] = 'This functionality will search for <a href="http://tracker.moodle.org/browse/MDL-29322">Oracle varchar2 columns using BYTE semantics</a> in your Moodle server, generating (but not executing!) automatically the needed SQL statements to have all the columns converted to use CHAR semantics instead (better for cross-db compatibility and increased contents max. length).
+
+Once generated you can copy such statements and execute them safely with your favourite SQL interface (don\'t forget to backup your data before doing that).
+
+It\'s highly recommended to be running the latest (+ version) available of your Moodle release before executing the search of BYTE semantics.
+
This functionality doesn\'t perform any action against the DB (just reads from it), so can be safely executed at any moment.';
$string['confirmrevertchanges'] = 'Are you absolutely sure that you want to revert changes performed over:';
$string['create'] = 'Create';
View
7 backup/util/ui/tests/behat/backup_courses.feature
@@ -13,8 +13,9 @@ Feature: Backup Moodle courses
@javascript
Scenario: Backup a course providing options
When I backup "Course 1" course using this options:
+ | Filename | test_backup.mbz |
Then I should see "Restore"
- And I click on "Restore" "link" in the ".backup-files-table" "css_element"
+ And I click on "Restore" "link" in the "test_backup.mbz" "table_row"
And I should see "URL of backup"
And I should see "Anonymize user information"
@@ -27,11 +28,11 @@ Feature: Backup Moodle courses
| setting_section_section_5_userinfo | 0 |
| setting_section_section_5_included | 0 |
Then I should see "Restore"
- And I click on "Restore" "link" in the ".backup-files-table" "css_element"
+ And I click on "Restore" "link" in the "test_backup.mbz" "table_row"
And I should not see "Section 3"
And I press "Continue"
And I click on "Continue" "button" in the ".bcs-current-course" "css_element"
And "//div[contains(concat(' ', normalize-space(@class), ' '), ' fitem ')][contains(., 'Include calendar events')]/descendant::img" "xpath_element" should exists
And I check "Include course logs"
And I press "Cancel"
- And I click on "Cancel" "button" in the ".confirmation-dialogue" "css_element"
+ And I click on "Cancel" "button" in the "Cancel backup" "dialogue"
View
51 badges/external.php
@@ -27,14 +27,59 @@
require_once(dirname(dirname(__FILE__)) . '/config.php');
require_once($CFG->libdir . '/badgeslib.php');
-$json = required_param('badge', PARAM_RAW);
+$json = optional_param('badge', null, PARAM_RAW);
+// Redirect to homepage if users are trying to access external badge through old url.
+if ($json) {
+ redirect($CFG->wwwroot, get_string('invalidrequest', 'error'), 3);
+}
+
+$hash = required_param('hash', PARAM_ALPHANUM);
+$userid = required_param('user', PARAM_INT);
+
+$PAGE->set_url(new moodle_url('/badges/external.php', array('hash' => $hash, 'user' => $userid)));
+
+// Using the same setting as user profile page.
+if (!empty($CFG->forceloginforprofiles)) {
+ require_login();
+ if (isguestuser()) {
+ $SESSION->wantsurl = $PAGE->url->out(false);
+ redirect(get_login_url());
+ }
+} else if (!empty($CFG->forcelogin)) {
+ require_login();
+}
+
+// Get all external badges of a user.
+$out = get_backpack_settings($userid);
+
+// If we didn't find any badges then print an error.
+if (is_null($out)) {
+ print_error('error:externalbadgedoesntexist', 'badges');
+}
+
+$badges = $out->badges;
+
+// The variable to store the badge we want.
+$badge = '';
+
+// Loop through the badges and check if supplied badge hash exists in user external badges.
+foreach ($badges as $b) {
+ if ($hash == hash("md5", $b->hostedUrl)) {
+ $badge = $b;
+ break;
+ }
+}
+
+// If we didn't find the badge a user might be trying to replace the userid parameter.
+if (empty($badge)) {
+ print_error('error:externalbadgedoesntexist', 'badges');
+}
$PAGE->set_context(context_system::instance());
$output = $PAGE->get_renderer('core', 'badges');
-$badge = new external_badge(unserialize($json));
+$badge = new external_badge($badge, $userid);
-$PAGE->set_url('/badges/external.php');
$PAGE->set_pagelayout('base');
$PAGE->set_title(get_string('issuedbadge', 'badges'));
View
3 badges/mybackpack.php
@@ -53,11 +53,13 @@
$PAGE->set_pagelayout('mydashboard');
$backpack = $DB->get_record('badge_backpack', array('userid' => $USER->id));
+$badgescache = cache::make('core', 'externalbadges');
if ($disconnect && $backpack) {
require_sesskey();
$DB->delete_records('badge_external', array('backpackid' => $backpack->id));
$DB->delete_records('badge_backpack', array('userid' => $USER->id));
+ $badgescache->delete($USER->id);
redirect(new moodle_url('/badges/mybackpack.php'));
}
@@ -103,6 +105,7 @@
$DB->insert_record('badge_external', $obj);
}
}
+ $badgescache->delete($USER->id);
redirect(new moodle_url('/badges/mybadges.php'));
}
} else {
View
99 badges/renderer.php
@@ -81,9 +81,10 @@ public function print_badges_list($badges, $userid, $profile = false, $external
$url = new moodle_url('badge.php', array('hash' => $badge->uniquehash));
} else {
if (!$external) {
- $url = new moodle_url($CFG->wwwroot . '/badges/badge.php', array('hash' => $badge->uniquehash));
+ $url = new moodle_url('/badges/badge.php', array('hash' => $badge->uniquehash));
} else {
- $url = new moodle_url($CFG->wwwroot . '/badges/external.php', array('badge' => serialize($badge)));
+ $hash = hash('md5', $badge->hostedUrl);
+ $url = new moodle_url('/badges/external.php', array('hash' => $hash, 'user' => $userid));
}
}
$actions = html_writer::tag('div', $push . $download . $status, array('class' => 'badge-actions'));
@@ -276,6 +277,7 @@ public function print_badge_table_actions($badge, $context) {
protected function render_issued_badge(issued_badge $ibadge) {
global $USER, $CFG, $DB;
$issued = $ibadge->issued;
+ $userinfo = $ibadge->recipient;
$badge = new badge($ibadge->badgeid);
$today_date = date('Y-m-d');
$today = strtotime($today_date);
@@ -286,7 +288,7 @@ protected function render_issued_badge(issued_badge $ibadge) {
$imagetable = new html_table();
$imagetable->attributes = array('class' => 'clearfix badgeissuedimage');
$imagetable->data[] = array(html_writer::empty_tag('img', array('src' => $issued['badge']['image'])));
- if ($USER->id == $ibadge->recipient && !empty($CFG->enablebadges)) {
+ if ($USER->id == $userinfo->id && !empty($CFG->enablebadges)) {
$imagetable->data[] = array($this->output->single_button(
new moodle_url('/badges/badge.php', array('hash' => $ibadge->hash, 'bake' => true)),
get_string('download'),
@@ -307,11 +309,20 @@ protected function render_issued_badge(issued_badge $ibadge) {
$datatable = new html_table();
$datatable->attributes = array('class' => 'badgeissuedinfo');
$datatable->colclasses = array('bfield', 'bvalue');
+
+ // Recipient information.
+ $datatable->data[] = array($this->output->heading(get_string('recipientdetails', 'badges'), 3), '');
+ $datatable->data[] = array(get_string('name'), fullname($userinfo));
+ if (empty($userinfo->backpackemail)) {
+ $datatable->data[] = array(get_string('email'), obfuscate_mailto($userinfo->accountemail));
+ } else {
+ $datatable->data[] = array(get_string('email'), obfuscate_mailto($userinfo->backpackemail));
+ }
+
$datatable->data[] = array($this->output->heading(get_string('issuerdetails', 'badges'), 3), '');
$datatable->data[] = array(get_string('issuername', 'badges'), $badge->issuername);
if (isset($badge->issuercontact) && !empty($badge->issuercontact)) {
- $datatable->data[] = array(get_string('contact', 'badges'),
- html_writer::tag('a', $badge->issuercontact, array('href' => 'mailto:' . $badge->issuercontact)));
+ $datatable->data[] = array(get_string('contact', 'badges'), obfuscate_mailto($badge->issuercontact));
}
$datatable->data[] = array($this->output->heading(get_string('badgedetails', 'badges'), 3), '');
$datatable->data[] = array(get_string('name'), $badge->name);
@@ -347,7 +358,7 @@ protected function render_issued_badge(issued_badge $ibadge) {
// Print evidence.
$agg = $badge->get_aggregation_methods();
- $evidence = $badge->get_criteria_completions($ibadge->recipient);
+ $evidence = $badge->get_criteria_completions($userinfo->id);
$eids = array_map(create_function('$o', 'return $o->critid;'), $evidence);
unset($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]);
@@ -378,6 +389,7 @@ protected function render_external_badge(external_badge $ibadge) {
$issued = $ibadge->issued;
$assertion = $issued->assertion;
$issuer = $assertion->badge->issuer;
+ $userinfo = $ibadge->recipient;
$table = new html_table();
$imagetable = new html_table();
@@ -387,13 +399,29 @@ protected function render_external_badge(external_badge $ibadge) {
$datatable = new html_table();
$datatable->attributes = array('class' => 'badgeissuedinfo');
$datatable->colclasses = array('bfield', 'bvalue');
+
+ // Recipient information.
+ $datatable->data[] = array($this->output->heading(get_string('recipientdetails', 'badges'), 3), '');
+ // Technically, we should alway have a user at this point, but added an extra check just in case.
+ if ($userinfo) {
+ $datatable->data[] = array(get_string('name'), fullname($userinfo));
+ if (!$ibadge->valid) {
+ $notify = $this->output->notification(get_string('recipientvalidationproblem', 'badges'), 'notifynotice');
+ $datatable->data[] = array(get_string('email'), obfuscate_mailto($userinfo->email) . $notify);
+ } else {
+ $datatable->data[] = array(get_string('email'), obfuscate_mailto($userinfo->email));
+ }
+ } else {
+ $notify = $this->output->notification(get_string('recipientidentificationproblem', 'badges'), 'notifynotice');
+ $datatable->data[] = array(get_string('name'), $notify);
+ }
+
$datatable->data[] = array($this->output->heading(get_string('issuerdetails', 'badges'), 3), '');
$datatable->data[] = array(get_string('issuername', 'badges'), $issuer->name);
$datatable->data[] = array(get_string('issuerurl', 'badges'),
html_writer::tag('a', $issuer->origin, array('href' => $issuer->origin)));
if (isset($issuer->contact)) {
- $datatable->data[] = array(get_string('contact', 'badges'),
- html_writer::tag('a', $issuer->contact, array('href' => 'mailto:' . $issuer->contact)));
+ $datatable->data[] = array(get_string('contact', 'badges'), obfuscate_mailto($issuer->contact));
}
$datatable->data[] = array($this->output->heading(get_string('badgedetails', 'badges'), 3), '');
$datatable->data[] = array(get_string('name'), $assertion->badge->name);
@@ -875,7 +903,7 @@ class issued_badge implements renderable {
public $issued;
/** @var badge recipient */
- public $recipient = 0;
+ public $recipient;
/** @var badge visibility to others */
public $visible = 0;
@@ -901,7 +929,12 @@ public function __construct($hash) {
WHERE ' . $DB->sql_compare_text('uniquehash', 40) . ' = ' . $DB->sql_compare_text(':hash', 40),
array('hash' => $hash), IGNORE_MISSING);
if ($rec) {
- $this->recipient = $rec->userid;
+ // Get a recipient from database.
+ $user = $DB->get_record_sql('SELECT u.id, u.lastname, u.firstname,
+ u.email AS accountemail, b.email AS backpackemail
+ FROM {user} u LEFT JOIN {badge_backpack} b ON u.id = b.userid
+ WHERE u.id = :userid', array('userid' => $rec->userid));
+ $this->recipient = $user;
$this->visible = $rec->visible;
$this->badgeid = $rec->badgeid;
}
@@ -915,13 +948,51 @@ class external_badge implements renderable {
/** @var issued badge */
public $issued;
+ /** @var User ID */
+ public $recipient;
+
+ /** @var validation of external badge */
+ public $valid = true;
+
/**
* Initializes the badge to display
*
- * @param string $json External badge information.
+ * @param object $badge External badge information.
+ * @param int $recipient User id.
*/
- public function __construct($json) {
- $this->issued = $json;
+ public function __construct($badge, $recipient) {
+ global $DB;
+ // At this point a user has connected a backpack. So, we are going to get
+ // their backpack email rather than their account email.
+ $user = $DB->get_record_sql('SELECT u.lastname, u.firstname, b.email
+ FROM {user} u INNER JOIN {badge_backpack} b ON u.id = b.userid
+ WHERE userid = :userid', array('userid' => $recipient), IGNORE_MISSING);
+
+ $this->issued = $badge;
+ $this->recipient = $user;
+
+ // Check if recipient is valid.
+ // There is no way to be 100% sure that a badge belongs to a user.
+ // Backpack does not return any recipient information.
+ // All we can do is compare that backpack email hashed using salt
+ // provided in the assertion matches a badge recipient from the assertion.
+ if ($user) {
+ if (validate_email($badge->assertion->recipient) && $badge->assertion->recipient == $user->email) {
+ // If we have email, compare emails.
+ $this->valid = true;
+ } else if ($badge->assertion->recipient == 'sha256$' . hash('sha256', $user->email)) {
+ // If recipient is hashed, but no salt, compare hashes without salt.
+ $this->valid = true;
+ } else if ($badge->assertion->recipient == 'sha256$' . hash('sha256', $user->email . $badge->assertion->salt)) {
+ // If recipient is hashed, compare hashes.
+ $this->valid = true;
+ } else {
+ // Otherwise, we cannot be sure that this user is a recipient.
+ $this->valid = false;
+ }
+ } else {
+ $this->valid = false;
+ }
}
}
@@ -1016,7 +1087,7 @@ public function __construct($badges, $userid) {
parent::__construct($badges);
if (!empty($CFG->badges_allowexternalbackpack)) {
- $this->backpack = get_backpack_settings($userid);
+ $this->backpack = get_backpack_settings($userid, true);
}
}
}
View
4 blocks/course_list/lang/en/block_course_list.php
@@ -26,9 +26,9 @@
$string['adminview'] = 'Admin view';
$string['allcourses'] = 'Admin user sees all courses';
$string['configadminview'] = 'What should the admin see in the course list block?';
-$string['confighideallcourseslink'] = 'Hide "All courses" link at the bottom of the block. Link hiding does not affects Admin\'s view';
+$string['confighideallcourseslink'] = 'Remove the \'All courses\' link under the list of courses. (This setting does not affect the admin view.)';
$string['course_list:addinstance'] = 'Add a new courses block';
$string['course_list:myaddinstance'] = 'Add a new courses block to My home';
-$string['hideallcourseslink'] = 'Hide All courses link';
+$string['hideallcourseslink'] = 'Hide \'All courses\' link';
$string['owncourses'] = 'Admin user sees own courses';
$string['pluginname'] = 'Courses';
View
34 blocks/navigation/tests/behat/view_my_courses.feature
@@ -38,14 +38,14 @@ Feature: View my courses in navigation block
And I log out
And I log in as "student1"
When I follow "My home"
- Then I should not see "cat1" in the "div.block_navigation .type_system" "css_element"
- And I should not see "cat2" in the "div.block_navigation .type_system" "css_element"
- And I should see "c1" in the "div.block_navigation .type_system" "css_element"
- And I should see "c31" in the "div.block_navigation .type_system" "css_element"
- And I should see "c331" in the "div.block_navigation .type_system" "css_element"
- And I should not see "c2" in the "div.block_navigation .type_system" "css_element"
- And I should not see "c32" in the "div.block_navigation .type_system" "css_element"
- And I should not see "c332" in the "div.block_navigation .type_system" "css_element"
+ Then I should not see "cat1" in the "Navigation" "block"
+ And I should not see "cat2" in the "Navigation" "block"
+ And I should see "c1" in the "Navigation" "block"
+ And I should see "c31" in the "Navigation" "block"
+ And I should see "c331" in the "Navigation" "block"
+ And I should not see "c2" in the "Navigation" "block"
+ And I should not see "c32" in the "Navigation" "block"
+ And I should not see "c332" in the "Navigation" "block"
@javascript
Scenario: The nested list of enrolled courses is shown
@@ -54,18 +54,18 @@ Feature: View my courses in navigation block
And I log out
And I log in as "student1"
When I follow "My home"
- Then I should see "cat1" in the "div.block_navigation .type_system" "css_element"
- And I should see "cat3" in the "div.block_navigation .type_system" "css_element"
- And I should not see "cat2" in the "div.block_navigation .type_system" "css_element"
+ Then I should see "cat1" in the "Navigation" "block"
+ And I should see "cat3" in the "Navigation" "block"
+ And I should not see "cat2" in the "Navigation" "block"
And I expand "cat3" node
And I wait "2" seconds
- And I should see "cat31" in the "div.block_navigation .type_system" "css_element"
- And I should see "cat33" in the "div.block_navigation .type_system" "css_element"
- And I should not see "cat32" in the "div.block_navigation .type_system" "css_element"
+ And I should see "cat31" in the "Navigation" "block"
+ And I should see "cat33" in the "Navigation" "block"
+ And I should not see "cat32" in the "Navigation" "block"
And I expand "cat31" node
And I wait "2" seconds
- And I should see "c31" in the "div.block_navigation .type_system" "css_element"
+ And I should see "c31" in the "Navigation" "block"
And I expand "cat33" node
And I wait "2" seconds
- And I should see "c331" in the "div.block_navigation .type_system" "css_element"
- And I should not see "c332" in the "div.block_navigation .type_system" "css_element"
+ And I should see "c331" in the "Navigation" "block"
+ And I should not see "c332" in the "Navigation" "block"
View
18 calendar/lib.php
@@ -111,6 +111,16 @@
define('CALENDAR_IMPORT_EVENT_INSERTED', 2);
/**
+ * CALENDAR_SUBSCRIPTION_UPDATE - Used to represent update action for subscriptions in various forms.
+ */
+define('CALENDAR_SUBSCRIPTION_UPDATE', 1);
+
+/**
+ * CALENDAR_SUBSCRIPTION_REMOVE - Used to represent remove action for subscriptions in various forms.
+ */
+define('CALENDAR_SUBSCRIPTION_REMOVE', 2);
+
+/**
* Return the days of the week
*
* @return array array of days
@@ -2894,17 +2904,13 @@ function calendar_add_icalendar_event($event, $courseid, $subscriptionid) {
* @return string A log of the import progress, including errors
*/
function calendar_process_subscription_row($subscriptionid, $pollinterval, $action) {
- global $DB;
// Fetch the subscription from the database making sure it exists.
$sub = calendar_get_subscription($subscriptionid);
- $strupdate = get_string('update');
- $strremove = get_string('remove');
-
// Update or remove the subscription, based on action.
switch ($action) {
- case $strupdate:
+ case CALENDAR_SUBSCRIPTION_UPDATE:
// Skip updating file subscriptions.
if (empty($sub->url)) {
break;
@@ -2915,7 +2921,7 @@ function calendar_process_subscription_row($subscriptionid, $pollinterval, $acti
// Update the events.
return "<p>".get_string('subscriptionupdated', 'calendar', $sub->name)."</p>" . calendar_update_subscription_events($subscriptionid);
- case $strremove:
+ case CALENDAR_SUBSCRIPTION_REMOVE:
calendar_delete_subscription($subscriptionid);
return get_string('subscriptionremoved', 'calendar', $sub->name);
break;
View
2 calendar/managesubscriptions.php
@@ -33,7 +33,7 @@
// Used for processing subscription actions.
$subscriptionid = optional_param('id', 0, PARAM_INT);
$pollinterval = optional_param('pollinterval', 0, PARAM_INT);
-$action = optional_param('action', '', PARAM_ALPHA);
+$action = optional_param('action', '', PARAM_INT);
$url = new moodle_url('/calendar/managesubscriptions.php');
if ($courseid != SITEID) {
View
6 calendar/renderer.php
@@ -836,9 +836,11 @@ protected function subscription_action_form($subscription, $courseid) {
$html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'course', 'value' => $courseid));
$html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'id', 'value' => $subscription->id));
if (!empty($subscription->url)) {
- $html .= html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'action', 'value' => get_string('update')));
+ $html .= html_writer::tag('button', get_string('update'), array('type' => 'submit', 'name' => 'action',
+ 'value' => CALENDAR_SUBSCRIPTION_UPDATE));
}
- $html .= html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'action', 'value' => get_string('remove')));
+ $html .= html_writer::tag('button', get_string('remove'), array('type' => 'submit', 'name' => 'action',
+ 'value' => CALENDAR_SUBSCRIPTION_REMOVE));
$html .= html_writer::end_tag('div');
$html .= html_writer::end_tag('form');
return $html;
View
8 course/tests/behat/course_controls.feature
@@ -74,8 +74,8 @@ Feature: Course activity controls works as expected
And section "1" should be visible
And I add the "Section links" block
And "#section-2" "css_element" <should_see_other_sections> exists
- And I should see "1 2 3 4 5" in the ".block_section_links" "css_element"
- And I click on "2" "link" in the ".block_section_links" "css_element"
+ And I should see "1 2 3 4 5" in the "Section links" "block"
+ And I click on "2" "link" in the "Section links" "block"
And I <should_see_other_sections_following_block_sections_links> see "Test forum name 2"
Examples:
@@ -148,8 +148,8 @@ Feature: Course activity controls works as expected
And section "1" should be visible
And I add the "Section links" block
And "#section-2" "css_element" <should_see_other_sections> exists
- And I should see "1 2 3 4 5" in the ".block_section_links" "css_element"
- And I click on "2" "link" in the ".block_section_links" "css_element"
+ And I should see "1 2 3 4 5" in the "Section links" "block"
+ And I click on "2" "link" in the "Section links" "block"
And I <should_see_other_sections_following_block_sections_links> see "Test forum name 2"
Examples:
View
1 enrol/ldap/lang/en/enrol_ldap.php
@@ -53,6 +53,7 @@
$string['createcourseextid'] = 'CREATE User enrolled to a nonexistant course \'{$a->courseextid}\'';
$string['createnotcourseextid'] = 'User enrolled to a nonexistant course \'{$a->courseextid}\'';
$string['creatingcourse'] = 'Creating course \'{$a}\'...';
+$string['duplicateshortname'] = "Course creation failed. Duplicate short name. Skipping course with idnumber '{\$a->idnumber}'...";
$string['editlock'] = 'Lock value';
$string['emptyenrolment'] = "Empty enrolment for role '{\$a->role_shortname}' in course '{\$a->course_shortname}'\n";
$string['enrolname'] = 'LDAP';
View
6 enrol/ldap/lib.php
@@ -990,6 +990,12 @@ function create_course($course_ext, progress_trace $trace) {
$course->summary = $course_ext[$this->get_config('course_summary')][0];
}
+ // Check if the shortname already exists if it does - skip course creation.
+ if ($DB->record_exists('course', array('shortname' => $course->shortname))) {
+ $trace->output(get_string('duplicateshortname', 'enrol_ldap', $course));
+ return false;
+ }
+
$newcourse = create_course($course);
return $newcourse->id;
}
View
2 error/index.php
@@ -49,9 +49,9 @@
header("Status: 404 Not Found");
$PAGE->set_url('/error/');
+ $PAGE->set_context(get_system_context());
$PAGE->set_title($site->fullname .':Error');
$PAGE->set_heading($site->fullname .': Error 404');
- $PAGE->set_context(get_system_context());
$PAGE->navbar->add('Error 404 - File not Found');
echo $OUTPUT->header();
echo $OUTPUT->box(get_string('pagenotexist', 'error'). '<br />'.s($requesturi), 'generalbox boxaligncenter');
View
10 files/renderer.php
@@ -201,9 +201,9 @@ private function fm_print_generallayout($fm) {
<div class="fp-navbar">
<div class="filemanager-toolbar">
<div class="fp-toolbar">
- <div class="{!}fp-btn-add"><a href="#"><img src="'.$this->pix_url('a/add_file').'" /> '.$straddfile.'</a></div>
- <div class="{!}fp-btn-mkdir"><a href="#"><img src="'.$this->pix_url('a/create_folder').'" /> '.$strmakedir.'</a></div>
- <div class="{!}fp-btn-download"><a href="#"><img src="'.$this->pix_url('a/download_all').'" /> '.$strdownload.'</a></div>
+ <div class="{!}fp-btn-add"><a role="button" href="#"><img src="'.$this->pix_url('a/add_file').'" /> '.$straddfile.'</a></div>
+ <div class="{!}fp-btn-mkdir"><a role="button" href="#"><img src="'.$this->pix_url('a/create_folder').'" /> '.$strmakedir.'</a></div>
+ <div class="{!}fp-btn-download"><a role="button" href="#"><img src="'.$this->pix_url('a/download_all').'" /> '.$strdownload.'</a></div>
</div>
<div class="{!}fp-viewbar">
<a title="'. get_string('displayicons', 'repository') .'" class="{!}fp-vb-icons" href="#"></a>
@@ -521,10 +521,10 @@ private function fm_print_restrictions($fm) {
*/
private function fp_js_template_generallayout() {
$rv = '
-<div class="file-picker fp-generallayout">
+<div tabindex="0" class="file-picker fp-generallayout" role="dialog" aria-live="assertive">
<div class="fp-repo-area">
<ul class="fp-list">
- <li class="{!}fp-repo"><a href="#"><img class="{!}fp-repo-icon" alt="'. get_string('repositoryicon', 'repository') .'" width="16" height="16" />&nbsp;<span class="{!}fp-repo-name"></span></a></li>
+ <li class="{!}fp-repo"><a href="#"><img class="{!}fp-repo-icon" alt=" " width="16" height="16" />&nbsp;<span class="{!}fp-repo-name"></span></a></li>
</ul>
</div>
<div class="fp-repo-items" tabindex="0">
View
2 grade/export/lib.php
@@ -189,7 +189,7 @@ public function format_column_name($grade_item, $feedback=false) {
$name .= ' ('.get_string('feedback').')';
}
- return strip_tags($name);
+ return html_to_text($name, 0, false);
}
/**
View
16 lang/en/admin.php
@@ -119,7 +119,7 @@
$string['commonsettings'] = 'Common settings';
$string['componentinstalled'] = 'Component installed';
$string['computedfromlogs'] = 'Computed from logs since {$a}.';
-$string['condifmodeditdefaults'] = 'The values you set here define the default values that are used in the activity settings form when you create a new activity. You can also configure which activity settings are considered advanced.';
+$string['condifmodeditdefaults'] = 'Default values are used in the settings form when creating a new activity or resource.';
$string['confeditorhidebuttons'] = 'Select the buttons that should be hidden in the HTML editor.';
$string['configallcountrycodes'] = 'This is the list of countries that may be selected in various places, for example in a user\'s profile. If blank (the default) the list in countries.php in the standard English language pack is used. That is the list from ISO 3166-1. Otherwise, you can specify a comma-separated list of codes, for example \'GB,FR,ES\'. If you add new, non-standard codes here, you will need to add them to countries.php in \'en\' and your language pack.';
$string['configallowassign'] = 'You can allow people who have the roles on the left side to assign some of the column roles to other people';
@@ -163,15 +163,15 @@
http://site.example.com/admin/cron.php?password=opensesame
</pre>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) and a tooltip title (optional), separated by pipe characters. You can specify a structure using hyphens. For example:
+$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. You can specify a structure using hyphens. For example:
<pre>
Moodle community|http://moodle.org
-Moodle free support|http://moodle.org/support
-Moodle development|http://moodle.org/development
--Moodle Tracker|http://tracker.moodle.org
---Moodle Docs|http://docs.moodle.org
--Moodle News|http://moodle.org/news
-Moodle company
+--Moodle Docs|http://docs.moodle.org|Moodle Docs in German
+--German Moodle Docs|http://docs.moodle.org/de|Documentation in German|de
+-Moodle News|http://moodle.org/news Moodle company
-Moodle commercial hosting|http://moodle.com/hosting
-Moodle commercial support|http://moodle.com/support
</pre>';
@@ -530,10 +530,10 @@
$string['filtersettings'] = 'Manage filters';
$string['filtersettingsgeneral'] = 'General filter settings';
$string['filteruploadedfiles'] = 'Filter uploaded files';
-$string['forcelogin'] = 'Force users to login';
-$string['forceloginforprofileimage'] = 'Force users to login to view user pictures';
+$string['forcelogin'] = 'Force users to log in';
+$string['forceloginforprofileimage'] = 'Force users to log in to view user pictures';
$string['forceloginforprofileimage_help'] = 'If enabled, users must login in order to view user profile pictures and the default user picture will be used in all notification emails.';
-$string['forceloginforprofiles'] = 'Force users to login for profiles';
+$string['forceloginforprofiles'] = 'Force users to log in for profiles';
$string['forcetimezone'] = 'Force default timezone';
$string['formatuninstallwithcourses'] = 'There are {$a->count} courses using {$a->format}. Their format will be changed to {$a->defaultformat} (default format for this site). Some format-specific data may be lost. Are you sure you want to proceed?';
$string['formatuninstallconfirm'] = '{$a} will be uninstalled. No courses currently use it. Continue?';
View
8 lang/en/badges.php
@@ -101,7 +101,9 @@
You can still control individual badge privacy settings on your "My badges" page.';
$string['badgeprivacysetting_str'] = 'Automatically show badges I earn on my profile page';
$string['badgesalt'] = 'Salt for hashing the recepient\'s email address';
-$string['badgesalt_desc'] = 'Using a hash allows backpack services to confirm the badge earner without having to expose their email address. This setting should only use numbers and letters.';
+$string['badgesalt_desc'] = 'Using a hash allows backpack services to confirm the badge earner without having to expose their email address. This setting should only use numbers and letters.
+
+Note: For recipient verification purposes, please avoid changing this setting once you start issuing badges.';
$string['badgesdisabled'] = 'Badges are not enabled on this site.';
$string['badgesearned'] = 'Number of badges earned: {$a}';
$string['badgesettings'] = 'Badges settings';
@@ -203,6 +205,7 @@
$string['error:cannotawardbadge'] = 'Cannot award badge to a user.';
$string['error:clone'] = 'Cannot clone the badge.';
$string['error:duplicatename'] = 'Badge with such name already exists in the system.';
+$string['error:externalbadgedoesntexist'] = 'Badge not found';
$string['error:invalidbadgeurl'] = 'Invalid badge issuer URL format.';
$string['error:invalidcriteriatype'] = 'Invalid criteria type.';
$string['error:invalidexpiredate'] = 'Expiry date has to be in the future.';
@@ -305,6 +308,9 @@
$string['overallcrit'] = 'of the selected criteria are complete.';
$string['potentialrecipients'] = 'Potential badge recipients';
$string['recipients'] = 'Badge recipients';
+$string['recipientdetails'] = 'Recipient details';
+$string['recipientidentificationproblem'] = 'Cannot find a recipient of this badge among the existing users.';
+$string['recipientvalidationproblem'] = 'Current user cannot be verified as a recipient of this badge.';
$string['relative'] = 'Relative date';
$string['requiredcourse'] = 'At least one course should be added to the courseset criterion.';
$string['reviewbadge'] = 'Review badge criteria';
View
1 lang/en/cache.php
@@ -44,6 +44,7 @@
$string['cachedef_coursecattree'] = 'Course categories tree';
$string['cachedef_databasemeta'] = 'Database meta information';
$string['cachedef_eventinvalidation'] = 'Event invalidation';
+$string['cachedef_externalbadges'] = 'External badges for particular user';
$string['cachedef_groupdata'] = 'Course group information';
$string['cachedef_htmlpurifier'] = 'HTML Purifier - cleaned content';
$string['cachedef_locking'] = 'Locking';
View
2 lang/en/completion.php
@@ -70,7 +70,7 @@
$string['completionexpected'] = 'Expect completed on';
$string['completionexpected_help'] = 'This setting specifies the date when the activity is expected to be completed. The date is not shown to students and is only displayed in the activity completion report.';
$string['completionicons'] = 'Completion tick boxes';
-$string['completionicons_help'] = 'A tick next an activity name may be used to indicate when the activity is complete.
+$string['completionicons_help'] = 'A tick next to an activity name may be used to indicate when the activity is complete.
If a box with a dotted border is shown, a tick will appear automatically when you have completed the activity according to conditions set by the teacher.
View
2 lang/en/error.php
@@ -219,7 +219,7 @@
$string['duplicateroleshortname'] = 'There is already a role with this short name!';
$string['duplicateusername'] = 'Duplicate username - skipping record';
$string['emailfail'] = 'Emailing failed';
-$string['error'] = 'Error occured';
+$string['error'] = 'Error occurred';
$string['errorcleaningdirectory'] = 'Error cleaning directory "{$a}"';
$string['errorcopyingfiles'] = 'Error copying files';
$string['errorcreatingdirectory'] = 'Error creating directory "{$a}"';
View
2 lang/en/install.php
@@ -38,7 +38,7 @@
renaming the admin directory in your installation, and putting that
new name here. For example: <br /> <br /><b>moodleadmin</b><br /> <br />
This will fix admin links in Moodle.';
-$string['availablelangs'] = 'List of available languages';
+$string['availablelangs'] = 'Available language packs';
$string['caution'] = 'Caution';
$string['cliadminpassword'] = 'New admin user password';
$string['cliadminusername'] = 'Admin account username';
View
2 lang/en/mathslib.php
@@ -23,7 +23,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-$string['anunexpectederroroccured'] = 'an unexpected error occured';
+$string['anunexpectederroroccured'] = 'an unexpected error occurred';
$string['cannotassigntoconstant'] = 'cannot assign to constant \'{$a}\'';
$string['cannotredefinebuiltinfunction'] = 'cannot redefine built-in function \'{$a}()\'';
$string['divisionbyzero'] = 'division by zero';
View
1 lang/en/moodle.php
@@ -333,6 +333,7 @@
If you use this area to store course files, you can expose yourself to a number of privacy and security issues, as well as experiencing missing files in backups, course imports and any time content is shared or re-used. It is therefore recommended that you do not use this area unless you really know what you are doing.';
$string['courselegacyfiles_link'] = 'coursefiles2';
+$string['courselegacyfilesofcourse'] = 'Legacy course files: {$a}';
$string['courseoverview'] = 'Course overview';
$string['courseoverviewgraph'] = 'Course overview graph';
$string['courseprofiles'] = 'Course profiles';
View
2 lang/en/repository.php
@@ -106,7 +106,7 @@
$string['erroruniquename'] = 'Repository instance name should be unique';
$string['errorpostmaxsize'] = 'The uploaded file may exceed the post_max_size directive in php.ini.';
$string['errorwhilecommunicatingwith'] = 'Error while communicating with the repository \'{$a}\'.';
-$string['errorwhiledownload'] = 'An error occured while downloading the file: {$a}';
+$string['errorwhiledownload'] = 'An error occurred while downloading the file: {$a}';
$string['existingrepository'] = 'This repository already exists';
$string['federatedsearch'] = 'Federated search';
$string['fileexists'] = 'File name already being used, please use another name';
View
15 lib/badgeslib.php
@@ -1167,13 +1167,25 @@ function badges_bake($hash, $badgeid, $userid = 0, $pathhash = false) {
/**
* Returns external backpack settings and badges from this backpack.
*
+ * This function first checks if badges for the user are cached and
+ * tries to retrieve them from the cache. Otherwise, badges are obtained
+ * through curl request to the backpack.
+ *
* @param int $userid Backpack user ID.
+ * @param boolean $refresh Refresh badges collection in cache.
* @return null|object Returns null is there is no backpack or object with backpack settings.
*/
-function get_backpack_settings($userid) {
+function get_backpack_settings($userid, $refresh = false) {
global $DB;
require_once(dirname(dirname(__FILE__)) . '/badges/lib/backpacklib.php');
+ // Try to get badges from cache first.
+ $badgescache = cache::make('core', 'externalbadges');
+ $out = $badgescache->get($userid);
+ if ($out !== false && !$refresh) {
+ return $out;
+ }
+ // Get badges through curl request to the backpack.
$record = $DB->get_record('badge_backpack', array('userid' => $userid));
if ($record) {
$backpack = new OpenBadgesBackpackHandler($record);
@@ -1198,6 +1210,7 @@ function get_backpack_settings($userid) {
$out->totalcollections = 0;
}
+ $badgescache->set($userid, $out);
return $out;
}
View
20 lib/behat/behat_base.php
@@ -367,22 +367,13 @@ protected function get_node_in_container($selectortype, $element, $containersele
*/
protected function transform_selector($selectortype, $element) {
- // Here we don't know if a $allowedtextselector is used.
- if (!isset(behat_command::$allowedselectors[$selectortype])) {
+ // Here we don't know if an allowed text selector is being used.
+ $selectors = behat_selectors::get_allowed_selectors();
+ if (!isset($selectors[$selectortype])) {
throw new ExpectationException('The "' . $selectortype . '" selector type does not exist', $this->getSession());
}
- // CSS and XPath selectors locator is one single argument.
- if ($selectortype == 'css_element' || $selectortype == 'xpath_element') {
- $selector = str_replace('_element', '', $selectortype);
- $locator = $element;
- } else {
- // Named selectors uses arrays as locators including the type of named selector.
- $locator = array($selectortype, $this->getSession()->getSelectorsHandler()->xpathLiteral($element));
- $selector = 'named';
- }
-
- return array($selector, $locator);
+ return behat_selectors::get_behat_selector($selectortype, $element, $this->getSession());
}
/**
@@ -398,7 +389,8 @@ protected function transform_selector($selectortype, $element) {
*/
protected function transform_text_selector($selectortype, $element) {
- if ($selectortype != 'css_element' && $selectortype != 'xpath_element') {
+ $selectors = behat_selectors::get_allowed_text_selectors();
+ if (empty($selectors[$selectortype])) {
throw new ExpectationException('The "' . $selectortype . '" selector can not be used to select text nodes', $this->getSession());
}
View
28 lib/behat/classes/behat_command.php
@@ -43,34 +43,6 @@ class behat_command {
const DOCS_URL = 'http://docs.moodle.org/dev/Acceptance_testing';
/**
- * @var Allowed types when using text selectors arguments.
- */
- public static $allowedtextselectors = array(
- 'css_element' => 'css_element',
- 'xpath_element' => 'xpath_element'
- );
-
- /**
- * @var Allowed types when using selector arguments.
- */
- public static $allowedselectors = array(
- 'link' => 'link',
- 'button' => 'button',
- 'link_or_button' => 'link_or_button',
- 'select' => 'select',
- 'checkbox' => 'checkbox',
- 'radio' => 'radio',
- 'file' => 'file',
- 'optgroup' => 'optgroup',
- 'option' => 'option',
- 'table' => 'table',
- 'field' => 'field',
- 'fieldset' => 'fieldset',
- 'css_element' => 'css_element',
- 'xpath_element' => 'xpath_element'
- );
-
- /**
* Ensures the behat dir exists in moodledata
* @return string Full path
*/
View
161 lib/behat/classes/behat_selectors.php
@@ -0,0 +1,161 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Moodle-specific selectors.
+ *
+ * @package core
+ * @category test
+ * @copyright 2013 David Monllaó
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Moodle selectors manager.
+ *
+ * @package core
+ * @category test
+ * @copyright 2013 David Monllaó
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_selectors {
+
+ /**
+ * @var Allowed types when using text selectors arguments.
+ */
+ protected static $allowedtextselectors = array(
+ 'dialogue' => 'dialogue',
+ 'block' => 'block',
+ 'region' => 'region',
+ 'table_row' => 'table_row',
+ 'table' => 'table',
+ 'fieldset' => 'fieldset',
+ 'css_element' => 'css_element',
+ 'xpath_element' => 'xpath_element'
+ );
+
+ /**
+ * @var Allowed types when using selector arguments.
+ */
+ protected static $allowedselectors = array(
+ 'dialogue' => 'dialogue',
+ 'block' => 'block',
+ 'region' => 'region',
+ 'table_row' => 'table_row',
+ 'link' => 'link',
+ 'button' => 'button',
+ 'link_or_button' => 'link_or_button',
+ 'select' => 'select',
+ 'checkbox' => 'checkbox',
+ 'radio' => 'radio',
+ 'file' => 'file',
+ 'optgroup' => 'optgroup',
+ 'option' => 'option',
+ 'table' => 'table',
+ 'field' => 'field',
+ 'fieldset' => 'fieldset',
+ 'css_element' => 'css_element',
+ 'xpath_element' => 'xpath_element'
+ );
+
+ /**
+ * Behat by default comes with XPath, CSS and named selectors,
+ * named selectors are a mapping between names (like button) and
+ * xpaths that represents that names and includes a placeholder that
+ * will be replaced by the locator. These are Moodle's own xpaths.
+ *
+ * @var XPaths for moodle elements.
+ */
+ protected static $moodleselectors = array(
+ 'dialogue' => <<<XPATH
+.//div[contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue ')]/descendant::h1[normalize-space(.) = %locator%]/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue ')]
+XPATH
+ , 'block' => <<<XPATH
+.//div[contains(concat(' ', normalize-space(@class), ' '), concat(' ', %locator%, ' '))] | .//div[contains(concat(' ', normalize-space(@class), ' '), ' block ')]/descendant::h2[normalize-space(.) = %locator%]/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' block ')]
+XPATH
+ , 'region' => <<<XPATH
+.//div[./@id = %locator%]
+XPATH
+ , 'table_row' => <<<XPATH
+.//tr[contains(normalize-space(.), %locator%)]
+XPATH
+ );
+
+ /**
+ * Returns the behat selector and locator for a given moodle selector and locator
+ *
+ * @param string $selectortype The moodle selector type, which includes moodle selectors
+ * @param string $element The locator we look for in that kind of selector
+ * @param Session $session The Mink opened session
+ * @return array Contains the selector and the locator expected by Mink.
+ */
+ public static function get_behat_selector($selectortype, $element, Behat\Mink\Session $session) {
+
+ // CSS and XPath selectors locator is one single argument.
+ if ($selectortype == 'css_element' || $selectortype == 'xpath_element') {
+ $selector = str_replace('_element', '', $selectortype);
+ $locator = $element;
+ } else {
+ // Named selectors uses arrays as locators including the type of named selector.
+ $locator = array($selectortype, $session->getSelectorsHandler()->xpathLiteral($element));
+ $selector = 'named';
+ }
+
+ return array($selector, $locator);
+ }
+
+ /**
+ * Adds moodle selectors as behat named selectors.
+ *
+ * @param Session $session The mink session
+ * @return void
+ */
+ public static function register_moodle_selectors(Behat\Mink\Session $session) {
+
+ foreach (self::get_moodle_selectors() as $name => $xpath) {
+ $session->getSelectorsHandler()->getSelector('named')->registerNamedXpath($name, $xpath);
+ }
+ }
+
+ /**
+ * Allowed selectors getter.
+ *
+ * @return array
+ */
+ public static function get_allowed_selectors() {
+ return self::$allowedselectors;
+ }
+
+ /**
+ * Allowed text selectors getter.
+ *
+ * @return array
+ */
+ public static function get_allowed_text_selectors() {
+ return self::$allowedtextselectors;
+ }
+
+ /**
+ * Moodle selectors attribute accessor.
+ *
+ * @return array
+ */
+ protected static function get_moodle_selectors() {
+ return self::$moodleselectors;
+ }
+}
View
2 lib/blocklib.php
@@ -993,7 +993,7 @@ protected function ensure_instances_exist($region) {
*
* @param string $region The name of the region to check
*/
- protected function ensure_content_created($region, $output) {
+ public function ensure_content_created($region, $output) {
$this->ensure_instances_exist($region);
if (!array_key_exists($region, $this->visibleblockcontent)) {
$contents = array();
View
3 lib/configonlylib.php
@@ -95,6 +95,9 @@ function min_fix_utf8($value) {
error_reporting($olderror ^ E_NOTICE);
}
+ // No null bytes expected in our data, so let's remove it.
+ $value = str_replace("\0", '', $value);
+
static $buggyiconv = null;
if ($buggyiconv === null) {
$buggyiconv = (!function_exists('iconv') or iconv('UTF-8', 'UTF-8//IGNORE', '100'.chr(130).'') !== '100€');
View
6 lib/db/caches.php
@@ -236,4 +236,10 @@
'mode' => cache_store::MODE_REQUEST,
'persistent' => true,
),
+ // Used to store external badges.
+ 'externalbadges' => array(
+ 'mode' => cache_store::MODE_APPLICATION,
+ 'simplekeys' => true,
+ 'ttl' => 3600,
+ ),
);
View
1 lib/dml/mssql_native_moodle_database.php
@@ -648,6 +648,7 @@ protected function emulate_bound_params($sql, array $params=null) {
} else {
$param = str_replace("'", "''", $param);
+ $param = str_replace("\0", "", $param);
$return .= "N'$param'";
}
View
1 lib/dml/sqlsrv_native_moodle_database.php
@@ -727,6 +727,7 @@ protected function emulate_bound_params($sql, array $params = null) {
$return .= $param;
} else {
$param = str_replace("'", "''", $param);
+ $param = str_replace("\0", "", $param);
$return .= "N'$param'";
}
View
7 lib/editor/tinymce/module.js
@@ -68,6 +68,13 @@ M.editor_tinymce.init_editor = function(Y, editorid, options) {
ed.contentDocument.addEventListener('keydown', function() {
ed.contentWindow.focus();
});
+
+ // Whenever a touch event is registered against the content document,
+ // reapply focus. This works around an issue with the location caret not
+ // being focusable without use of the Loupe.
+ ed.contentDocument.addEventListener('touchend', function() {
+ ed.contentWindow.focus();
+ });
});
};
}
View
8 lib/ldaplib.php
@@ -247,9 +247,11 @@ function ldap_find_userdn($ldapconnection, $username, $contexts, $objectclass, $
}
if ($search_sub) {
- $ldap_result = ldap_search($ldapconnection, $context,
- '(&'.$objectclass.'('.$search_attrib.'='.ldap_filter_addslashes($username).'))',
- array($search_attrib));
+ if (!$ldap_result = @ldap_search($ldapconnection, $context,
+ '(&'.$objectclass.'('.$search_attrib.'='.ldap_filter_addslashes($username).'))',
+ array($search_attrib))) {
+ break; // Not found in this context.
+ }
} else {
$ldap_result = ldap_list($ldapconnection, $context,
'(&'.$objectclass.'('.$search_attrib.'='.ldap_filter_addslashes($username).'))',
View
5 lib/modinfolib.php
@@ -1274,7 +1274,8 @@ public function is_user_access_restricted_by_capability() {
}
// You are blocked if you don't have the capability.
- return !has_capability($capability, context_module::instance($this->id));
+ $userid = $this->modinfo->get_user_id();
+ return !has_capability($capability, context_module::instance($this->id), $userid);
}
/**
@@ -1283,7 +1284,7 @@ public function is_user_access_restricted_by_capability() {
* @return bool True if the user cannot see the module. False if the activity is either available or should be greyed out.
*/
public function is_user_access_restricted_by_conditional_access() {
- global $CFG, $USER;
+ global $CFG;
if (empty($CFG->enableavailability)) {
return false;
View
2 lib/moodlelib.php
@@ -1181,6 +1181,8 @@ function fix_utf8($value) {
// shortcut
return $value;
}
+ // No null bytes expected in our data, so let's remove it.
+ $value = str_replace("\0", '', $value);
// Lower error reporting because glibc throws bogus notices.
$olderror = error_reporting();
View
10 lib/outputrenderers.php
@@ -345,6 +345,16 @@ public function htmlattributes() {
*/
public function standard_head_html() {
global $CFG, $SESSION;
+
+ // Before we output any content, we need to ensure that certain
+ // page components are set up.
+
+ // Blocks must be set up early as they may require javascript which
+ // has to be included in the page header before output is created.
+ foreach ($this->page->blocks->get_regions() as $region) {
+ $this->page->blocks->ensure_content_created($region, $this);
+ }
+
$output = '';
$output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />' . "\n";
$output .= '<meta name="keywords" content="moodle, ' . $this->page->title . '" />' . "\n";
View
6 lib/tests/behat/behat_hooks.php
@@ -89,6 +89,7 @@ public static function before_suite($event) {
// Now that we are MOODLE_INTERNAL.
require_once(__DIR__ . '/../../behat/classes/behat_command.php');
+ require_once(__DIR__ . '/../../behat/classes/behat_selectors.php');
require_once(__DIR__ . '/../../behat/classes/util.php');
require_once(__DIR__ . '/../../testing/classes/test_lock.php');
require_once(__DIR__ . '/../../testing/classes/nasty_strings.php');
@@ -138,6 +139,11 @@ public function before_scenario($event) {
throw new coding_exception('Behat only can modify the test database and the test dataroot!');
}
+ // We need the Mink session to do it and we do it only before the first scenario.
+ if (self::is_first_scenario()) {
+ behat_selectors::register_moodle_selectors($this->getSession());
+ }
+
// Avoid some notices / warnings.
$SESSION = new stdClass();
View
2 lib/tests/configonlylib_test.php
@@ -44,7 +44,7 @@ class core_configonlylib_testcase extends advanced_testcase {
*/
public function test_min_fix_utf8() {
$this->assertSame('abc', min_fix_utf8('abc'));
- $this->assertSame("žlutý koníček přeskočil potůček \n\t\r\0", min_fix_utf8("žlutý koníček přeskočil potůček \n\t\r\0"));
+ $this->assertSame("žlutý koníček přeskočil potůček \n\t\r", min_fix_utf8("žlutý koníček přeskočil potůček \n\t\r\0"));
$this->assertSame('', min_fix_utf8('a'.chr(130).'š'), 'This fails with buggy iconv() when mbstring extenstion is not available as fallback.');
}
View
55 lib/tests/modinfolib_test.php
@@ -176,6 +176,61 @@ public function test_is_user_access_restricted_by_conditional_access() {
$this->assertFalse($cm_info->is_user_access_restricted_by_conditional_access());
}
+ public function test_is_user_access_restricted_by_capability() {
+ global $DB;
+
+ $this->resetAfterTest();
+
+ // Create a course and a mod_assign instance.
+ $course = $this->getDataGenerator()->create_course();
+ $assign = $this->getDataGenerator()->create_module('assign', array('course'=>$course->id));
+
+ // Create and enrol a student.
+ $coursecontext = context_course::instance($course->id);
+ $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
+ $student = $this->getDataGenerator()->create_user();
+ role_assign($studentrole->id, $student->id, $coursecontext);
+ $enrolplugin = enrol_get_plugin('manual');
+ $enrolinstance = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'manual'));
+ $enrolplugin->enrol_user($enrolinstance, $student->id);
+ $this->setUser($student);
+
+ // Make sure student can see the module.
+ $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
+ $this->assertTrue($cm->uservisible);
+ $this->assertFalse($cm->is_user_access_restricted_by_capability());
+
+ // Prohibit student to view mod_assign for the course.
+ role_change_permission($studentrole->id, $coursecontext, 'mod/assign:view', CAP_PROHIBIT);
+ get_fast_modinfo($course->id, 0, true);
+ $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
+ $this->assertFalse($cm->uservisible);
+ $this->assertTrue($cm->is_user_access_restricted_by_capability());
+
+ // Restore permission to student to view mod_assign for the course.
+ role_change_permission($studentrole->id, $coursecontext, 'mod/assign:view', CAP_INHERIT);
+ get_fast_modinfo($course->id, 0, true);
+ $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
+ $this->assertTrue($cm->uservisible);
+ $this->assertFalse($cm->is_user_access_restricted_by_capability());
+
+ // Prohibit student to view mod_assign for the particular module.
+ role_change_permission($studentrole->id, context_module::instance($cm->id), 'mod/assign:view', CAP_PROHIBIT);
+ get_fast_modinfo($course->id, 0, true);
+ $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
+ $this->assertFalse($cm->uservisible);
+ $this->assertTrue($cm->is_user_access_restricted_by_capability());
+
+ // Check calling get_fast_modinfo() for different user:
+ $this->setAdminUser();
+ $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
+ $this->assertTrue($cm->uservisible);
+ $this->assertFalse($cm->is_user_access_restricted_by_capability());
+ $cm = get_fast_modinfo($course->id, $student->id)->instances['assign'][$assign->id];
+ $this->assertFalse($cm->uservisible);
+ $this->assertTrue($cm->is_user_access_restricted_by_capability());
+ }
+
private function refresh_cm_info($course, $assign) {
get_fast_modinfo(0, 0, true);
return get_fast_modinfo($course)->instances['assign'][$assign->id];
View
2 lib/tests/moodlelib_test.php
@@ -486,7 +486,7 @@ function test_fix_utf8() {
$this->assertEquals($object, fix_utf8($object));
// valid utf8 string
- $this->assertSame("žlutý koníček přeskočil potůček \n\t\r\0", fix_utf8("žlutý koníček přeskočil potůček \n\t\r\0"));
+ $this->assertSame("žlutý koníček přeskočil potůček \n\t\r", fix_utf8("žlutý koníček přeskočil potůček \n\t\r\0"));
// invalid utf8 string
$this->assertSame('aš', fix_utf8('a'.chr(130).'š'), 'This fails with buggy iconv() when mbstring extenstion is not available as fallback.');
View
2 lib/upgrade.txt
@@ -2,6 +2,8 @@ This files describes API changes in core libraries and APIs,
information provided here is intended especially for developers.
=== 2.5.2 ===
* Use new function moodleform::mock_submit() to simulate form submission in unit tests.
+* Use behat_selectors::get_allowed_text_selectors() and behat_selectors::get_allowed_selectors() instead of
+ behat_command::$allowedtextselectors and behat_command::$allowedselectors
=== 2.5.1 ===
View
2 login/change_password.php
@@ -41,7 +41,7 @@
if ($return) {
// this redirect prevents security warning because https can not POST to http pages
if (empty($SESSION->wantsurl)
- or stripos(str_replace('https://', 'http://', $SESSION->wantsurl), str_replace('https://', 'http://', $CFG->wwwroot.'/login/change_password.php') === 0)) {
+ or stripos(str_replace('https://', 'http://', $SESSION->wantsurl), str_replace('https://', 'http://', $CFG->wwwroot.'/login/change_password.php')) === 0) {
$returnto = "$CFG->wwwroot/user/view.php?id=$USER->id&course=$id";
} else {
$returnto = $SESSION->wantsurl;
View
4 mod/assign/backup/moodle2/restore_assign_stepslib.php
@@ -94,6 +94,10 @@ protected function process_assign($data) {
$data->cutoffdate = $this->apply_date_offset($data->cutoffdate);
}
+ if ($data->grade < 0) { // Scale found, get mapping.
+ $data->grade = -($this->get_mappingid('scale', abs($data->grade)));
+ }
+
$newitemid = $DB->insert_record('assign', $data);
$this->apply_activity_instance($newitemid);
View
11 mod/assign/locallib.php
@@ -3660,9 +3660,10 @@ protected function gradebook_item_update($submission=null, $grade=null) {
$team = groups_get_members($submission->groupid, 'u.id');
foreach ($team as $member) {
- $submission->groupid = 0;
- $submission->userid = $member->id;
- $this->gradebook_item_update($submission, null);
+ $membersubmission = clone $submission;
+ $membersubmission->groupid = 0;
+ $membersubmission->userid = $member->id;
+ $this->gradebook_item_update($membersubmission, null);
}
return;
}
@@ -5324,7 +5325,7 @@ protected function process_lock($userid = 0) {
// Give each submission plugin a chance to process the locking.
$plugins = $this->get_submission_plugins();
- $submission = $this->get_user_submission($userid, false);
+ $submission = $this->get_user_submission($userid, true);
foreach ($plugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
$plugin->lock($submission);
@@ -5361,7 +5362,7 @@ protected function process_unlock($userid = 0) {
}
// Give each submission plugin a chance to process the unlocking.
$plugins = $this->get_submission_plugins();
- $submission = $this->get_user_submission($userid, false);
+ $submission = $this->get_user_submission($userid, true);
foreach ($plugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
$plugin->unlock($submission);
View
9 mod/assignment/backup/moodle1/lib.php
@@ -194,7 +194,8 @@ protected function get_subplugin_handler($subplugin) {
}
if (!isset($this->subpluginhandlers[$subplugin])) {
- throw new moodle1_convert_exception('unsupported_subplugin', 'assignment_'.$subplugin);
+ // Generic handling, prevents breaking conversion process...
+ $this->subpluginhandlers[$subplugin] = new moodle1_assignment_unsupported_subplugin_handler($this, $subplugin);
}
return $this->subpluginhandlers[$subplugin];
@@ -236,4 +237,10 @@ public function append_subplugin_data($data) {
//you will probably want to do stuff with $this->xmlwriter here (within your overridden method) to write plugin specific data.
}
+}
+
+/**
+ * This class handles subplugins that do not exist or that are not supported
+ */
+class moodle1_assignment_unsupported_subplugin_handler extends moodle1_assignment_subplugin_handler {
}
View
20 mod/assignment/backup/moodle2/restore_assignment_stepslib.php
@@ -72,6 +72,11 @@ protected function process_assignment($data) {
$newitemid = $DB->insert_record('assignment', $data);
// immediately after inserting "activity" record, call this
$this->apply_activity_instance($newitemid);
+
+ // Hide unsupported sub-plugins
+ if (!$this->is_valid_assignment_subplugin($data->assignmenttype)) {
+ $DB->set_field('course_modules', 'visible', 0, array('id' => $this->get_task()->get_moduleid()));
+ }
}
protected function process_assignment_submission($data) {
@@ -100,4 +105,19 @@ protected function after_execute() {
$this->add_related_files('mod_assignment', 'submission', 'assignment_submission');
$this->add_related_files('mod_assignment', 'response', 'assignment_submission');
}
+
+ /**
+ * Determine if a sub-plugin is supported or not
+ *