Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge remote branch 'moodle/MOODLE_20_STABLE' into m20_MDL-18392_slas…

…h_cleanup
  • Loading branch information...
commit dbb6157aa12b346c4189c0ed93aaa686b748dc63 2 parents 26daa23 + 50467e5
Dan Marsden danmarsden authored

Showing 94 changed files with 1,571 additions and 668 deletions. Show diff stats Hide diff stats

  1. +1 1  admin/cli/upgrade.php
  2. +1 1  admin/index.php
  3. +14 5 admin/settings/frontpage.php
  4. +26 28 admin/settings/users.php
  5. +1 1  admin/uploaduser.php
  6. +1 13 backup/util/ui/backup_ui.class.php
  7. +3 3 backup/util/ui/backup_ui_stage.class.php
  8. +15 0 backup/util/ui/base_ui.class.php
  9. +2 2 backup/util/ui/restore_ui_stage.class.php
  10. +3 0  blocks/comments/block_comments.php
  11. +3 2 comment/comment.js
  12. +163 77 comment/lib.php
  13. +6 0 enrol/ajax.php
  14. +2 0  enrol/locallib.php
  15. +6 2 enrol/renderer.php
  16. +3 1 enrol/users.php
  17. +15 1 enrol/yui/enrolmentmanager/enrolmentmanager.js
  18. +1 3 lang/en/admin.php
  19. +1 0  lang/en/enrol.php
  20. +1 0  lang/en/repository.php
  21. +4 4 lib/accesslib.php
  22. +10 0 lib/completionlib.php
  23. +2 2 lib/form/filemanager.js
  24. +6 5 lib/form/filemanager.php
  25. +84 8 lib/gradelib.php
  26. +116 163 lib/grouplib.php
  27. +3 3 lib/htmlpurifier/HTMLPurifier.php
  28. +2 0  lib/htmlpurifier/HTMLPurifier.safe-includes.php
  29. +138 13 lib/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php
  30. +9 0 lib/htmlpurifier/HTMLPurifier/AttrDef/CSS/URI.php
  31. +6 0 lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php
  32. +41 0 lib/htmlpurifier/HTMLPurifier/AttrTransform/Nofollow.php
  33. +2 1  lib/htmlpurifier/HTMLPurifier/AttrTransform/SafeParam.php
  34. +8 2 lib/htmlpurifier/HTMLPurifier/Bootstrap.php
  35. +21 0 lib/htmlpurifier/HTMLPurifier/CSSDefinition.php
  36. +181 52 lib/htmlpurifier/HTMLPurifier/Config.php
  37. +7 1 lib/htmlpurifier/HTMLPurifier/ConfigSchema.php
  38. BIN  lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema.ser
  39. +12 0 lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt
  40. +9 0 lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt
  41. +11 0 lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt
  42. +7 0 lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt
  43. +1 0  lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt
  44. +15 0 lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt
  45. +11 0 lib/htmlpurifier/HTMLPurifier/Definition.php
  46. +24 11 lib/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer.php
  47. 0  lib/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer/README
  48. +1 1  lib/htmlpurifier/HTMLPurifier/EntityLookup/entities.ser
  49. +38 13 lib/htmlpurifier/HTMLPurifier/Generator.php
  50. +19 0 lib/htmlpurifier/HTMLPurifier/HTMLModule/Nofollow.php
  51. +1 1  lib/htmlpurifier/HTMLPurifier/HTMLModule/SafeEmbed.php
  52. +0 1  lib/htmlpurifier/HTMLPurifier/HTMLModule/SafeObject.php
  53. +4 4 lib/htmlpurifier/HTMLPurifier/HTMLModuleManager.php
  54. +3 3 lib/htmlpurifier/HTMLPurifier/Lexer.php
  55. +52 22 lib/htmlpurifier/HTMLPurifier/Lexer/DOMLex.php
  56. +79 22 lib/htmlpurifier/HTMLPurifier/Strategy/MakeWellFormed.php
  57. +9 7 lib/htmlpurifier/HTMLPurifier/TagTransform/Font.php
  58. +2 1  lib/htmlpurifier/HTMLPurifier/Token/Tag.php
  59. +62 31 lib/htmlpurifier/HTMLPurifier/URI.php
  60. +54 7 lib/htmlpurifier/HTMLPurifier/URIScheme.php
  61. +4 1 lib/htmlpurifier/HTMLPurifier/URIScheme/data.php
  62. +8 2 lib/htmlpurifier/HTMLPurifier/URIScheme/file.php
  63. +1 2  lib/htmlpurifier/HTMLPurifier/URIScheme/ftp.php
  64. +1 2  lib/htmlpurifier/HTMLPurifier/URIScheme/http.php
  65. +2 2 lib/htmlpurifier/HTMLPurifier/URIScheme/mailto.php
  66. +2 2 lib/htmlpurifier/HTMLPurifier/URIScheme/news.php
  67. +1 2  lib/htmlpurifier/HTMLPurifier/URIScheme/nntp.php
  68. +2 3 lib/htmlpurifier/readme_moodle.txt
  69. +1 1  lib/installlib.php
  70. +4 0 lib/setuplib.php
  71. +133 0 lib/simpletest/testpurifier.php
  72. +0 25 lib/simpletest/testweblib.php
  73. +1 1  lib/thirdpartylibs.xml
  74. +14 12 lib/weblib.php
  75. +3 11 lib/xhprof/xhprof_moodle.php
  76. +11 13 message/output/email/message_output_email.php
  77. +1 1  mod/assignment/mod_form.php
  78. +4 3 mod/chat/view.php
  79. +4 5 mod/choice/view.php
  80. +1 0  mod/data/templates.php
  81. +4 5 mod/data/view.php
  82. +4 4 mod/feedback/complete.php
  83. +4 4 mod/feedback/lib.php
  84. +5 2 mod/forum/view.php
  85. +4 5 mod/glossary/view.php
  86. +1 1  mod/lesson/locallib.php
  87. +4 4 mod/lesson/view.php
  88. +4 6 mod/quiz/view.php
  89. +4 4 mod/scorm/player.php
  90. +4 3 mod/workshop/view.php
  91. +11 10 tag/lib.php
  92. +0 6 theme/canvas/style/editor.css
  93. +0 6 theme/canvas/style/text.css
  94. +2 2 version.php
2  admin/cli/upgrade.php
@@ -94,7 +94,7 @@
94 94 $newversion = "$release ($version)";
95 95
96 96 // test environment first
97   -if (!check_moodle_environment($version, $environment_results, false, ENV_SELECT_RELEASE)) {
  97 +if (!check_moodle_environment(normalize_version($release), $environment_results, false, ENV_SELECT_RELEASE)) {
98 98 $errors = environment_get_errors($environment_results);
99 99 cli_heading(get_string('environment', 'admin'));
100 100 foreach ($errors as $error) {
2  admin/index.php
@@ -152,7 +152,7 @@
152 152 echo $OUTPUT->box($releasenoteslink, 'generalbox releasenoteslink');
153 153
154 154 require_once($CFG->libdir.'/environmentlib.php');
155   - if (!check_moodle_environment($release, $environment_results, true, ENV_SELECT_RELEASE)) {
  155 + if (!check_moodle_environment(normalize_version($release), $environment_results, true, ENV_SELECT_RELEASE)) {
156 156 print_upgrade_reload("index.php?agreelicense=1&lang=$CFG->lang");
157 157 } else {
158 158 echo $OUTPUT->notification(get_string('environmentok', 'admin'), 'notifysuccess');
19 admin/settings/frontpage.php
@@ -52,13 +52,22 @@
52 52 $temp->add(new admin_setting_configtext('coursesperpage', get_string('coursesperpage', 'admin'), get_string('configcoursesperpage', 'admin'), 20, PARAM_INT));
53 53
54 54 // front page default role
55   - $roleoptions = array(0=>get_string('none')); // roles to choose from
56   - if ($roles = get_all_roles()) {
57   - foreach ($roles as $role) {
58   - $roleoptions[$role->id] = strip_tags(format_string($role->name, true));
  55 + $options = array(0=>get_string('none')); // roles to choose from
  56 + $defaultfrontpageroleid = 0;
  57 + foreach (get_all_roles() as $role) {
  58 + if (empty($role->archetype) or $role->archetype === 'guest' or $role->archetype === 'frontpage' or $role->archetype === 'student') {
  59 + $options[$role->id] = strip_tags(format_string($role->name)) . ' ('. $role->shortname . ')';
  60 + if ($role->archetype === 'frontpage') {
  61 + $defaultfrontpageroleid = $role->id;
  62 + }
59 63 }
60 64 }
61   - $temp->add(new admin_setting_configselect('defaultfrontpageroleid', get_string('frontpagedefaultrole', 'admin'), '', 0, $roleoptions));
  65 + if ($defaultfrontpageroleid and (!isset($CFG->defaultfrontpageroleid) or $CFG->defaultfrontpageroleid)) {
  66 + //frotpage role may not exist in old upgraded sites
  67 + unset($options[0]);
  68 + }
  69 + $temp->add(new admin_setting_configselect('defaultfrontpageroleid', get_string('frontpagedefaultrole', 'admin'), '', $defaultfrontpageroleid, $options));
  70 +
62 71
63 72 $ADMIN->add('frontpage', $temp);
64 73
54 admin/settings/users.php
@@ -38,17 +38,18 @@
38 38 if ($ADMIN->fulltree) {
39 39 if (!during_initial_install()) {
40 40 $context = get_context_instance(CONTEXT_SYSTEM);
41   - $allroles = array();
42   - $generalroles = array();
  41 +
  42 + $otherroles = array();
43 43 $guestroles = array();
44 44 $userroles = array();
45   - $studentroles = array();
46   - $teacherroles = array();
47 45 $creatornewroles = array();
48 46
  47 + $defaultteacherid = null;
  48 + $defaultuserid = null;
  49 + $defaultguestid = null;
  50 +
49 51 foreach (get_all_roles() as $role) {
50 52 $rolename = strip_tags(format_string($role->name)) . ' ('. $role->shortname . ')';
51   - $allroles[$role->id] = $rolename;
52 53 switch ($role->archetype) {
53 54 case 'manager':
54 55 $creatornewroles[$role->id] = $rolename;
@@ -56,58 +57,55 @@
56 57 case 'coursecreator':
57 58 break;
58 59 case 'editingteacher':
59   - $teacherroles[$role->id] = $rolename;
  60 + $defaultteacherid = isset($defaultteacherid) ? $defaultteacherid : $role->id;
60 61 $creatornewroles[$role->id] = $rolename;
61 62 break;
62 63 case 'teacher':
63 64 $creatornewroles[$role->id] = $rolename;
64 65 break;
65 66 case 'student':
66   - $studentroles[$role->id] = $rolename;
67 67 break;
68 68 case 'guest':
  69 + $defaultguestid = isset($defaultguestid) ? $defaultguestid : $role->id;
69 70 $guestroles[$role->id] = $rolename;
70 71 break;
71 72 case 'user':
  73 + $defaultuserid = isset($defaultuserid) ? $defaultuserid : $role->id;
72 74 $userroles[$role->id] = $rolename;
73 75 break;
74 76 case 'frontpage':
75 77 break;
76 78 default:
77 79 $creatornewroles[$role->id] = $rolename;
78   - $generalroles[$role->id] = $rolename;
  80 + $otherroles[$role->id] = $rolename;
79 81 break;
80 82 }
81 83 }
82 84
83   - reset($guestroles);
84   - $defaultguestid = key($guestroles);
85   - reset($studentroles);
86   - $defaultstudentid = key($studentroles);
87   - reset($teacherroles);
88   - $defaultteacherid = key($teacherroles);
89   -
90   - if ($userroles) {
91   - reset($userroles);
92   - $defaultuserid = key($userroles);
93   - } else {
94   - $userroles = array('0'=>get_string('none'));
  85 + if (empty($guestroles)) {
  86 + $guestroles[0] = get_string('none');
  87 + $defaultguestid = 0;
  88 + }
  89 +
  90 + if (empty($userroles)) {
  91 + $userroles[0] = get_string('none');
95 92 $defaultuserid = 0;
96 93 }
97 94
98 95 $temp->add(new admin_setting_configselect('notloggedinroleid', get_string('notloggedinroleid', 'admin'),
99   - get_string('confignotloggedinroleid', 'admin'), $defaultguestid, ($guestroles + $generalroles)));
  96 + get_string('confignotloggedinroleid', 'admin'), $defaultguestid, ($guestroles + $otherroles)));
100 97 $temp->add(new admin_setting_configselect('guestroleid', get_string('guestroleid', 'admin'),
101   - get_string('guestroleid_help', 'admin'), $defaultguestid, ($guestroles + $generalroles)));
  98 + get_string('guestroleid_help', 'admin'), $defaultguestid, ($guestroles + $otherroles)));
102 99 $temp->add(new admin_setting_configselect('defaultuserroleid', get_string('defaultuserroleid', 'admin'),
103   - get_string('configdefaultuserroleid', 'admin'), $defaultuserid, ($userroles + $generalroles)));
104   - }
105   -
106   - $temp->add(new admin_setting_configcheckbox('nodefaultuserrolelists', get_string('nodefaultuserrolelists', 'admin'), get_string('confignodefaultuserrolelists', 'admin'), 0));
107   -
108   - if (!during_initial_install()) {
  100 + get_string('configdefaultuserroleid', 'admin'), $defaultuserid, ($userroles + $otherroles)));
109 101 $temp->add(new admin_setting_configselect('creatornewroleid', get_string('creatornewroleid', 'admin'),
110 102 get_string('creatornewroleid_help', 'admin'), $defaultteacherid, $creatornewroles));
  103 +
  104 + // release memory
  105 + unset($otherroles);
  106 + unset($guestroles);
  107 + unset($userroles);
  108 + unset($creatornewroles);
111 109 }
112 110
113 111 $temp->add(new admin_setting_configcheckbox('autologinguests', get_string('autologinguests', 'admin'), get_string('configautologinguests', 'admin'), 0));
2  admin/uploaduser.php
@@ -774,7 +774,7 @@
774 774 }
775 775 }
776 776
777   - $manual->enrol_user($manualcache[$courseid], $user->id, $rid, $today, $timeend, true);
  777 + $manual->enrol_user($manualcache[$courseid], $user->id, $rid, $today, $timeend);
778 778
779 779 $a = new stdClass();
780 780 $a->course = $shortname;
14 backup/util/ui/backup_ui.class.php
@@ -130,19 +130,7 @@ public function execute() {
130 130 }
131 131 return $backupid;
132 132 }
133   - /**
134   - * Cancels the current backup and redirects the user back to the relevant place
135   - */
136   - public function cancel_backup() {
137   - global $PAGE;
138   - // Determine the approriate URL to redirect the user to
139   - if ($PAGE->context->contextlevel == CONTEXT_MODULE && $PAGE->cm !== null) {
140   - $relevanturl = new moodle_url('/mod/'.$PAGE->cm->modname.'/view.php', array('id'=>$PAGE->cm->id));
141   - } else {
142   - $relevanturl = new moodle_url('/course/view.php', array('id'=>$PAGE->course->id));
143   - }
144   - redirect($relevanturl);
145   - }
  133 +
146 134 /**
147 135 * Gets an array of progress bar items that can be displayed through the backup renderer.
148 136 * @return array Array of items for the progress bar
6 backup/util/ui/backup_ui_stage.class.php
@@ -81,7 +81,7 @@ public function process(base_moodleform $m = null) {
81 81 $form = $this->initialise_stage_form();
82 82
83 83 if ($form->is_cancelled()) {
84   - $this->ui->cancel_backup();
  84 + $this->ui->cancel_process();
85 85 }
86 86
87 87 $data = $form->get_data();
@@ -180,7 +180,7 @@ public function process(base_moodleform $form = null) {
180 180 $form = $this->initialise_stage_form();
181 181 // Check it wasn't cancelled
182 182 if ($form->is_cancelled()) {
183   - $this->ui->cancel_backup();
  183 + $this->ui->cancel_process();
184 184 }
185 185
186 186 // Check it has been submit
@@ -288,7 +288,7 @@ public function process(base_moodleform $form = null) {
288 288 $form = $this->initialise_stage_form();
289 289 // Check it hasn't been cancelled
290 290 if ($form->is_cancelled()) {
291   - $this->ui->cancel_backup();
  291 + $this->ui->cancel_process();
292 292 }
293 293
294 294 $data = $form->get_data();
15 backup/util/ui/base_ui.class.php
@@ -226,6 +226,21 @@ public function enforce_changed_dependencies() {
226 226 public static function load_controller($uniqueid=false) {
227 227 throw new coding_exception('load_controller() method needs to be overridden in each subclass of base_ui');
228 228 }
  229 +
  230 + /**
  231 + * Cancels the current backup/restore and redirects the user back to the relevant place
  232 + */
  233 + public function cancel_process() {
  234 + global $PAGE;
  235 + // Determine the appropriate URL to redirect the user to
  236 + if ($PAGE->context->contextlevel == CONTEXT_MODULE && $PAGE->cm !== null) {
  237 + $relevanturl = new moodle_url('/mod/'.$PAGE->cm->modname.'/view.php', array('id'=>$PAGE->cm->id));
  238 + } else {
  239 + $relevanturl = new moodle_url('/course/view.php', array('id'=>$PAGE->course->id));
  240 + }
  241 + redirect($relevanturl);
  242 + }
  243 +
229 244 /**
230 245 * Gets an array of progress bar items that can be displayed through the backup renderer.
231 246 * @return array Array of items for the progress bar
4 backup/util/ui/restore_ui_stage.class.php
@@ -392,7 +392,7 @@ public function process(base_moodleform $form = null) {
392 392 $form = $this->initialise_stage_form();
393 393 // Check it wasn't cancelled
394 394 if ($form->is_cancelled()) {
395   - $this->ui->cancel_backup();
  395 + $this->ui->cancel_process();
396 396 }
397 397
398 398 // Check it has been submit
@@ -500,7 +500,7 @@ public function process(base_moodleform $form = null) {
500 500 $form = $this->initialise_stage_form();
501 501 // Check it hasn't been cancelled
502 502 if ($form->is_cancelled()) {
503   - $this->ui->cancel_backup();
  503 + $this->ui->cancel_process();
504 504 }
505 505
506 506 $data = $form->get_data();
3  blocks/comments/block_comments.php
@@ -47,6 +47,9 @@ function get_content() {
47 47 $args->env = 'block_comments';
48 48 $args->component = 'block_comments';
49 49 $args->linktext = get_string('showcomments');
  50 + $args->notoggle = true;
  51 + $args->autostart = true;
  52 + $args->displaycancel = true;
50 53 $comment = new comment($args);
51 54 $comment->set_view_permission(true);
52 55
5 comment/comment.js
@@ -41,8 +41,9 @@ M.core_comment = {
41 41 this.courseid = args.courseid;
42 42 this.contextid = args.contextid;
43 43 this.env = args.env;
  44 + this.autostart = (args.autostart);
44 45 // expand comments?
45   - if (args.autostart) {
  46 + if (this.autostart) {
46 47 this.view(args.page);
47 48 }
48 49 // load comments
@@ -347,7 +348,7 @@ bodyContent: '<div class="comment-delete-confirm"><a href="#" id="confirmdelete-
347 348 var d = container.getStyle('display');
348 349 if (d=='none'||d=='') {
349 350 // show
350   - if (this.env != 'block_comments') {
  351 + if (this.autostart) {
351 352 this.load(page);
352 353 } else {
353 354 this.register_delete_buttons();
240 comment/lib.php
@@ -80,6 +80,26 @@ class comment {
80 80 */
81 81 private $linktext;
82 82
  83 + /**
  84 + * If set to true then comment sections won't be able to be opened and closed
  85 + * instead they will always be visible.
  86 + * @var bool
  87 + */
  88 + protected $notoggle = false;
  89 +
  90 + /**
  91 + * If set to true comments are automatically loaded as soon as the page loads.
  92 + * Normally this happens when the user expands the comment section.
  93 + * @var bool
  94 + */
  95 + protected $autostart = false;
  96 +
  97 + /**
  98 + * If set to true a cancel button will be shown on the form used to submit comments.
  99 + * @var bool
  100 + */
  101 + protected $displaycancel = false;
  102 +
83 103 // static variable will be used by non-js comments UI
84 104 private static $nonjs = false;
85 105 private static $comment_itemid = null;
@@ -87,6 +107,7 @@ class comment {
87 107 private static $comment_area = null;
88 108 private static $comment_page = null;
89 109 private static $comment_component = null;
  110 +
90 111 /**
91 112 * Construct function of comment class, initialise
92 113 * class members
@@ -173,6 +194,21 @@ public function __construct($options) {
173 194 $this->ignore_permission = false;
174 195 }
175 196
  197 + // setup notoggle
  198 + if (!empty($options->notoggle)) {
  199 + $this->set_notoggle($options->notoggle);
  200 + }
  201 +
  202 + // setup notoggle
  203 + if (!empty($options->autostart)) {
  204 + $this->set_autostart($options->autostart);
  205 + }
  206 +
  207 + // setup displaycancel
  208 + if (!empty($options->displaycancel)) {
  209 + $this->set_displaycancel($options->displaycancel);
  210 + }
  211 +
176 212 if (!empty($options->showcount)) {
177 213 $count = $this->count();
178 214 if (empty($count)) {
@@ -265,114 +301,164 @@ private function check_permissions() {
265 301 }
266 302
267 303 /**
  304 + * Gets a link for this page that will work with JS disabled.
  305 + *
  306 + * @global moodle_page $PAGE
  307 + * @param moodle_page $page
  308 + * @return moodle_url
  309 + */
  310 + public function get_nojslink(moodle_page $page = null) {
  311 + if ($page === null) {
  312 + global $PAGE;
  313 + $page = $PAGE;
  314 + }
  315 +
  316 + $link = new moodle_url($page->url, array(
  317 + 'nonjscomment' => true,
  318 + 'comment_itemid' => $this->itemid,
  319 + 'comment_context' => $this->context->id,
  320 + 'comment_area' => $this->commentarea,
  321 + ));
  322 + $link->remove_params(array('nonjscomment', 'comment_page'));
  323 + return $link;
  324 + }
  325 +
  326 + /**
  327 + * Sets the value of the notoggle option.
  328 + *
  329 + * If set to true then the user will not be able to expand and collase
  330 + * the comment section.
  331 + *
  332 + * @param bool $newvalue
  333 + */
  334 + public function set_notoggle($newvalue = true) {
  335 + $this->notoggle = (bool)$newvalue;
  336 + }
  337 +
  338 + /**
  339 + * Sets the value of the autostart option.
  340 + *
  341 + * If set to true then the comments will be loaded during page load.
  342 + * Normally this happens only once the user expands the comment section.
  343 + *
  344 + * @param bool $newvalue
  345 + */
  346 + public function set_autostart($newvalue = true) {
  347 + $this->autostart = (bool)$newvalue;
  348 + }
  349 +
  350 + /**
  351 + * Sets the displaycancel option
  352 + *
  353 + * If set to true then a cancel button will be shown when using the form
  354 + * to post comments.
  355 + *
  356 + * @param bool $newvalue
  357 + */
  358 + public function set_displaycancel($newvalue = true) {
  359 + $this->displaycancel = (bool)$newvalue;
  360 + }
  361 +
  362 + /**
  363 + * Initialises the JavaScript that enchances the comment API.
  364 + *
  365 + * @param moodle_page $page The moodle page object that the JavaScript should be
  366 + * initialised for.
  367 + */
  368 + public function initialise_javascript(moodle_page $page) {
  369 +
  370 + $options = new stdClass;
  371 + $options->client_id = $this->cid;
  372 + $options->commentarea = $this->commentarea;
  373 + $options->itemid = $this->itemid;
  374 + $options->page = 0;
  375 + $options->courseid = $this->courseid;
  376 + $options->contextid = $this->contextid;
  377 + $options->env = $this->env;
  378 + $options->component = $this->component;
  379 + $options->notoggle = $this->notoggle;
  380 + $options->autostart = $this->autostart;
  381 +
  382 + $page->requires->js_init_call('M.core_comment.init', array($options), true);
  383 +
  384 + return true;
  385 + }
  386 +
  387 + /**
268 388 * Prepare comment code in html
269 389 * @param boolean $return
270 390 * @return mixed
271 391 */
272 392 public function output($return = true) {
273 393 global $PAGE, $OUTPUT;
274   - static $template_printed;
275   -
276   - $this->link = $PAGE->url;
277   - $murl = new moodle_url($this->link);
278   - $murl->remove_params('nonjscomment');
279   - $murl->param('nonjscomment', 'true');
280   - $murl->param('comment_itemid', $this->itemid);
281   - $murl->param('comment_context', $this->context->id);
282   - $murl->param('comment_area', $this->commentarea);
283   - $murl->remove_params('comment_page');
284   - $this->link = $murl->out();
285   -
286   - $options = new stdClass();
287   - $options->client_id = $this->cid;
288   - $options->commentarea = $this->commentarea;
289   - $options->itemid = $this->itemid;
290   - $options->page = 0;
291   - $options->courseid = $this->courseid;
292   - $options->contextid = $this->contextid;
293   - $options->env = $this->env;
294   - $options->component = $this->component;
295   - if ($this->env == 'block_comments') {
296   - $options->notoggle = true;
297   - $options->autostart = true;
298   - }
  394 + static $template_printed;
299 395
300   - $PAGE->requires->js_init_call('M.core_comment.init', array($options), true);
  396 + $this->initialise_javascript($PAGE);
301 397
302 398 if (!empty(self::$nonjs)) {
303 399 // return non js comments interface
304 400 return $this->print_comments(self::$comment_page, $return, true);
305 401 }
306 402
307   - $strsubmit = get_string('savecomment');
308   - $strcancel = get_string('cancel');
309   - $strshowcomments = get_string('showcommentsnonjs');
310   - $sesskey = sesskey();
311 403 $html = '';
  404 +
312 405 // print html template
313 406 // Javascript will use the template to render new comments
314 407 if (empty($template_printed) && !empty($this->viewcap)) {
315   - $html .= '<div style="display:none" id="cmt-tmpl">' . $this->template . '</div>';
  408 + $html .= html_writer::tag('div', $this->template, array('style' => 'display:none', 'id' => 'cmt-tmpl'));
316 409 $template_printed = true;
317 410 }
318 411
319 412 if (!empty($this->viewcap)) {
320 413 // print commenting icon and tooltip
321   - $icon = $OUTPUT->pix_url('t/collapsed');
322   - $html .= <<<EOD
323   -<div class="mdl-left">
324   -<a class="showcommentsnonjs" href="{$this->link}">{$strshowcomments}</a>
325   -EOD;
326   - if ($this->env != 'block_comments') {
327   - $html .= <<<EOD
328   -<a id="comment-link-{$this->cid}" class="comment-link" href="#">
329   - <img id="comment-img-{$this->cid}" src="$icon" alt="{$this->linktext}" title="{$this->linktext}" />
330   - <span id="comment-link-text-{$this->cid}">{$this->linktext} {$this->count}</span>
331   -</a>
332   -EOD;
  414 + $html .= html_writer::start_tag('div', array('class' => 'mdl-left'));
  415 + $html .= html_writer::link($this->get_nojslink($PAGE), get_string('showcommentsnonjs'), array('class' => 'showcommentsnonjs'));
  416 +
  417 + if (!$this->notoggle) {
  418 + // If toggling is enabled (notoggle=false) then print the controls to toggle
  419 + // comments open and closed
  420 + $html .= html_writer::start_tag('a', array('class' => 'comment-link', 'id' => 'comment-link-'.$this->cid, 'href' => '#'));
  421 + $html .= html_writer::empty_tag('img', array('id' => 'comment-img-'.$this->cid, 'src' => $OUTPUT->pix_url('t/collapsed'), 'alt' => $this->linktext, 'title' => $this->linktext));
  422 + $html .= html_writer::tag('span', $this->linktext.' '.$this->count, array('id' => 'comment-link-text-'.$this->cid));
  423 + $html .= html_writer::end_tag('a');
333 424 }
334 425
335   - $html .= <<<EOD
336   -<div id="comment-ctrl-{$this->cid}" class="comment-ctrl">
337   - <ul id="comment-list-{$this->cid}" class="comment-list">
338   - <li class="first"></li>
339   -EOD;
340   - // in comments block, we print comments list right away
341   - if ($this->env == 'block_comments') {
  426 + $html .= html_writer::start_tag('div', array('id' => 'comment-ctrl-'.$this->cid, 'class' => 'comment-ctrl'));
  427 + $html .= html_writer::start_tag('ul', array('id' => 'comment-list-'.$this->cid, 'class' => 'comment-list'));
  428 + $html .= html_writer::tag('li', '', array('class' => 'first'));
  429 +
  430 + if ($this->autostart) {
  431 + // If autostart has been enabled print the comments list immediatly
342 432 $html .= $this->print_comments(0, true, false);
343   - $html .= '</ul>';
  433 + $html .= html_writer::end_tag('ul'); // .comment-list
344 434 $html .= $this->get_pagination(0);
345 435 } else {
346   - $html .= <<<EOD
347   - </ul>
348   - <div id="comment-pagination-{$this->cid}" class="comment-pagination"></div>
349   -EOD;
  436 + $html .= html_writer::end_tag('ul'); // .comment-list
  437 + $html .= html_writer::tag('div', '', array('id' => 'comment-pagination-'.$this->cid, 'class' => 'comment-pagination'));
350 438 }
351 439
352   - // print posting textarea
353 440 if (!empty($this->postcap)) {
354   - $html .= <<<EOD
355   -<div class='comment-area'>
356   - <div class="bd">
357   - <textarea name="content" rows="2" cols="20" id="dlg-content-{$this->cid}"></textarea>
358   - </div>
359   - <div class="fd" id="comment-action-{$this->cid}">
360   - <a href="#" id="comment-action-post-{$this->cid}"> {$strsubmit} </a>
361   -EOD;
362   - if ($this->env != 'block_comments') {
363   - $html .= "<span> | </span><a href=\"#\" id=\"comment-action-cancel-{$this->cid}\"> {$strcancel} </a>";
  441 + // print posting textarea
  442 + $html .= html_writer::start_tag('div', array('class' => 'comment-area'));
  443 + $html .= html_writer::start_tag('div', array('class' => 'db'));
  444 + $html .= html_writer::tag('textarea', '', array('name' => 'content', 'rows' => 2, 'cols' => 20, 'id' => 'dlg-content-'.$this->cid));
  445 + $html .= html_writer::end_tag('div'); // .db
  446 +
  447 + $html .= html_writer::start_tag('div', array('class' => 'fd', 'id' => 'comment-action-'.$this->cid));
  448 + $html .= html_writer::link('#', get_string('savecomment'), array('id' => 'comment-action-post-'.$this->cid));
  449 +
  450 + if ($this->displaycancel) {
  451 + $html .= html_writer::tag('span', ' | ');
  452 + $html .= html_writer::link('#', get_string('cancel'), array('id' => 'comment-action-cancel-'.$this->cid));
364 453 }
365   - $html .= <<<EOD
366   - </div>
367   -</div>
368   -<div class="clearer"></div>
369   -EOD;
  454 +
  455 + $html .= html_writer::end_tag('div'); // .fd
  456 + $html .= html_writer::end_tag('div'); // .comment-area
  457 + $html .= html_writer::tag('div', '', array('class' => 'clearer'));
370 458 }
371 459
372   - $html .= <<<EOD
373   -</div><!-- end of comment-ctrl -->
374   -</div>
375   -EOD;
  460 + $html .= html_writer::end_tag('div'); // .comment-ctrl
  461 + $html .= html_writer::end_tag('div'); // .mdl-left
376 462 } else {
377 463 $html = '';
378 464 }
@@ -457,11 +543,11 @@ public function get_pagination($page = 0) {
457 543 $count = $this->count();
458 544 $pages = (int)ceil($count/$CFG->commentsperpage);
459 545 if ($pages == 1 || $pages == 0) {
460   - return '';
  546 + return html_writer::tag('div', '', array('id' => 'comment-pagination-'.$this->cid, 'class' => 'comment-pagination'));
461 547 }
462 548 if (!empty(self::$nonjs)) {
463 549 // used in non-js interface
464   - return $OUTPUT->paging_bar($count, $page, $CFG->commentsperpage, $this->link, 'comment_page');
  550 + return $OUTPUT->paging_bar($count, $page, $CFG->commentsperpage, $this->get_nojslink(), 'comment_page');
465 551 } else {
466 552 // return ajax paging bar
467 553 $str = '';
6 enrol/ajax.php
@@ -154,6 +154,8 @@
154 154 $roleid = optional_param('role', null, PARAM_INT);
155 155 $duration = optional_param('duration', 0, PARAM_INT);
156 156 $startdate = optional_param('startdate', 0, PARAM_INT);
  157 + $recovergrades = optional_param('recovergrades', 0, PARAM_INT);
  158 +
157 159 if (empty($roleid)) {
158 160 $roleid = null;
159 161 }
@@ -185,6 +187,10 @@
185 187 $plugin = $plugins[$instance->enrol];
186 188 if ($plugin->allow_enrol($instance) && has_capability('enrol/'.$plugin->get_name().':enrol', $context)) {
187 189 $plugin->enrol_user($instance, $user->id, $roleid, $timestart, $timeend);
  190 + if ($recovergrades) {
  191 + require_once($CFG->libdir.'/gradelib.php');
  192 + grade_recover_history_grades($user->id, $instance->courseid);
  193 + }
188 194 } else {
189 195 throw new enrol_ajax_exception('enrolnotpermitted');
190 196 }
2  enrol/locallib.php
@@ -613,6 +613,8 @@ public function get_group($groupid) {
613 613 * @return bool
614 614 */
615 615 public function edit_enrolment($userenrolment, $data) {
  616 + //Only allow editing if the user has the appropriate capability
  617 + //Already checked in /enrol/users.php but checking again in case this function is called from elsewhere
616 618 list($instance, $plugin) = $this->get_user_enrolment_components($userenrolment);
617 619 if ($instance && $plugin && $plugin->allow_manage($instance) && has_capability("enrol/$instance->enrol:manage", $this->context)) {
618 620 if (!isset($data->status)) {
8 enrol/renderer.php
@@ -626,6 +626,7 @@ public function get_cohort_enrolment_control() {
626 626 * @return single_button|url_select
627 627 */
628 628 public function get_enrolment_selector() {
  629 + global $CFG;
629 630 static $count = 0;
630 631
631 632 $instances = $this->manager->get_enrolment_instances();
@@ -659,6 +660,7 @@ public function get_enrolment_selector() {
659 660 $control->class = 'singlebutton enrolusersbutton instance'.$count;
660 661 $control->formid = 'manuallyenrol_select_'+$count;
661 662 }
  663 +
662 664 $course = $this->manager->get_course();
663 665 $timeformat = get_string('strftimedatefullshort');
664 666 $today = time();
@@ -686,7 +688,8 @@ public function get_enrolment_selector() {
686 688 'startdatetoday',
687 689 'durationdays',
688 690 'enrolperiod',
689   - 'finishenrollingusers'), 'enrol');
  691 + 'finishenrollingusers',
  692 + 'recovergrades'), 'enrol');
690 693 $this->moodlepage->requires->string_for_js('assignroles', 'role');
691 694 $this->moodlepage->requires->string_for_js('startingfrom', 'moodle');
692 695
@@ -698,7 +701,8 @@ public function get_enrolment_selector() {
698 701 'ajaxurl'=>'/enrol/ajax.php',
699 702 'url'=>$this->moodlepage->url->out(false),
700 703 'optionsStartDate'=>$startdateoptions,
701   - 'defaultRole'=>$instance->roleid);
  704 + 'defaultRole'=>$instance->roleid,
  705 + 'disableGradeHistory'=>$CFG->disablegradehistory);
702 706 $this->moodlepage->requires->yui_module($modules, $function, array($arguments));
703 707 }
704 708 return $control;
4 enrol/users.php
@@ -62,7 +62,7 @@
62 62
63 63 switch ($action) {
64 64 /**
65   - * Unenrols a user from this course
  65 + * Unenrols a user from this course (including removing all of their grades)
66 66 */
67 67 case 'unenrol':
68 68 $ue = $DB->get_record('user_enrolments', array('id'=>required_param('ue', PARAM_INT)), '*', MUST_EXIST);
@@ -166,6 +166,8 @@
166 166 */
167 167 case 'edit':
168 168 $ue = $DB->get_record('user_enrolments', array('id'=>required_param('ue', PARAM_INT)), '*', MUST_EXIST);
  169 +
  170 + //Only show the edit form if the user has the appropriate capability
169 171 list($instance, $plugin) = $manager->get_user_enrolment_components($ue);
170 172 if ($instance && $plugin && $plugin->allow_manage($instance) && has_capability("enrol/$instance->enrol:manage", $manager->get_context())) {
171 173 $user = $DB->get_record('user', array('id'=>$ue->userid), '*', MUST_EXIST);
16 enrol/yui/enrolmentmanager/enrolmentmanager.js
@@ -20,7 +20,8 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) {
20 20 DEFAULTROLE : 'defaultRole',
21 21 DEFAULTSTARTDATE : 'defaultStartDate',
22 22 DEFAULTDURATION : 'defaultDuration',
23   - ASSIGNABLEROLES : 'assignableRoles'
  23 + ASSIGNABLEROLES : 'assignableRoles',
  24 + DISABLEGRADEHISTORY : 'disableGradeHistory'
24 25 };
25 26 /** CSS classes for nodes in structure **/
26 27 var CSS = {
@@ -48,6 +49,8 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) {
48 49 ODD : 'odd',
49 50 EVEN : 'even',
50 51 HIDDEN : 'hidden',
  52 + RECOVERGRADESCHECK : 'uep-recovergradescheck',
  53 + RECOVERGRADESCHECKTITLE : 'uep-recovergradeschecktitle',
51 54 SEARCHOPTIONS : 'uep-searchoptions',
52 55 COLLAPSIBLEHEADING : 'collapsibleheading',
53 56 COLLAPSIBLEAREA : 'collapsiblearea',
@@ -70,6 +73,11 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) {
70 73 _loadingNode : null,
71 74 _escCloseEvent : null,
72 75 initializer : function(config) {
  76 + recovergradescheckbox = null;
  77 + if (this.get(UEP.DISABLEGRADEHISTORY) != true) {
  78 + recovergradescheckbox = Y.Node.create('<div class="'+CSS.RECOVERGRADESCHECK+'"><input type="checkbox" id="recovergrades" name="recovergrades" /><span class="'+CSS.RECOVERGRADESCHECKTITLE+'"><label for="recovergrades">'+M.str.enrol.recovergrades+'</label></span></div>');
  79 + }
  80 +
73 81 this.set(UEP.BASE, Y.Node.create('<div class="'+CSS.PANEL+' '+CSS.HIDDEN+'"></div>')
74 82 .append(Y.Node.create('<div class="'+CSS.WRAP+'"></div>')
75 83 .append(Y.Node.create('<div class="'+CSS.HEADER+' header"></div>')
@@ -80,6 +88,7 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) {
80 88 .append(Y.Node.create('<div class="'+CSS.SEARCHOPTION+' '+CSS.ROLE+'">'+M.str.role.assignroles+'</div>')
81 89 .append(Y.Node.create('<select><option value="">'+M.str.enrol.none+'</option></select>'))
82 90 )
  91 + .append(recovergradescheckbox)
83 92 .append(Y.Node.create('<div class="'+CSS.SEARCHOPTIONS+'"></div>')
84 93 .append(Y.Node.create('<div class="'+CSS.COLLAPSIBLEHEADING+'"><img alt="" />'+M.str.enrol.enrolmentoptions+'</div>'))
85 94 .append(Y.Node.create('<div class="'+CSS.COLLAPSIBLEAREA+' '+CSS.HIDDEN+'"></div>')
@@ -367,6 +376,8 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) {
367 376 params['role'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.ROLE+' select').get('value');
368 377 params['startdate'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.STARTDATE+' select').get('value');
369 378 params['duration'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.DURATION+' select').get('value');
  379 + params['recovergrades'] = this.get(UEP.BASE).one('#recovergrades').get('checked')?1:0;
  380 +
370 381 Y.io(M.cfg.wwwroot+this.get(UEP.AJAXURL), {
371 382 method:'POST',
372 383 data:build_querystring(params),
@@ -487,6 +498,9 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) {
487 498 },
488 499 optionsStartDate : {
489 500 value : []
  501 + },
  502 + disableGradeHistory : {
  503 + value : 0
490 504 }
491 505 }
492 506 });
4 lang/en/admin.php
@@ -183,7 +183,7 @@
183 183 $string['configdefaulthomepage'] = 'This determines the home page for logged in users';
184 184 $string['configdefaultrequestcategory'] = 'Courses requested by users will be automatically placed in this category.';
185 185 $string['configdefaultrequestedcategory'] = 'Default category to put courses that were requested into, if they\'re approved.';
186   -$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 (or Guest role in older versions). Note that this will not conflict with other roles they have, it just ensures that all users have capabilities that are not assignable at the course level (eg post blog entries, manage own calendar, etc).';
  186 +$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).';
187 187 $string['configdeleteincompleteusers'] = 'After this period, old not fully setup accounts are deleted.';
188 188 $string['configdeleteunconfirmed'] = 'If you are using email authentication, this is the period within which a response will be accepted from users. After this period, old unconfirmed accounts are deleted.';
189 189 $string['configdenyemailaddresses'] = 'To deny email addresses from particular domains list them here in the same way. All other domains will be accepted. To deny subdomains add the domain with a preceding \'.\'. eg <strong>hotmail.com yahoo.co.uk .live.com</strong>';
@@ -276,7 +276,6 @@
276 276 $string['confignavcourselimit'] = 'Limits the number of courses shown to the user when they are either not logged in or are not enrolled in any courses.';
277 277 $string['confignavshowallcourses'] = 'Setting this ensures that all courses on the site are shown in the navigation at all times.';
278 278 $string['confignavshowcategories'] = 'Show course categories in the navigation bar and navigation blocks. This does not occur with courses the user is currently enrolled in, they will still be listed under mycourses without categories.';
279   -$string['confignodefaultuserrolelists'] = 'This setting prevents all users from being returned from the database from deprecated calls of get_course_user, etc., for the site course if the default role provides that access. Check this, if you suffer a performance hit.';
280 279 $string['confignoreplyaddress'] = 'Emails are sometimes sent out on behalf of a user (eg forum posts). The email address you specify here will be used as the "From" address in those cases when the recipients should not be able to reply directly to the user (eg when a user chooses to keep their address private).';
281 280 $string['confignotifyloginfailures'] = 'If login failures have been recorded, email notifications can be sent out. Who should see these notifications?';
282 281 $string['confignotifyloginthreshold'] = 'If notifications about failed logins are active, how many failed login attempts by one user or one IP address is it worth notifying about?';
@@ -747,7 +746,6 @@
747 746 $string['neverdeleteruns'] = 'Never delete runs';
748 747 $string['nobookmarksforuser'] = 'You do not have any bookmarks.';
749 748 $string['nodatabase'] = 'No database';
750   -$string['nodefaultuserrolelists'] = 'Don\'t return all default role users';
751 749 $string['nochanges'] = 'No changes';
752 750 $string['nolangupdateneeded'] = 'All your language packs are up to date, no update is needed';
753 751 $string['nomissingstrings'] = 'No missing strings';
1  lang/en/enrol.php
@@ -77,6 +77,7 @@
77 77 $string['periodend'] = 'until {$a}';
78 78 $string['periodstart'] = 'from {$a}';
79 79 $string['periodstartend'] = 'from {$a->start} until {$a->end}';
  80 +$string['recovergrades'] = 'Recover user\'s old grades if possible';
80 81 $string['rolefromthiscourse'] = '{$a->role} (Assigned in this course)';
81 82 $string['rolefrommetacourse'] = '{$a->role} (Inherited from parent course)';
82 83 $string['rolefromcategory'] = '{$a->role} (Inherited from course category)';
1  lang/en/repository.php
@@ -123,6 +123,7 @@
123 123 $string['manage'] = 'Manage repositories';
124 124 $string['manageurl'] = 'Manage';
125 125 $string['manageuserrepository'] = 'Manage individual repository';
  126 +$string['moving'] = 'Moving';
126 127 $string['noenter'] = 'Nothing entered';
127 128 $string['nofilesattached'] = 'No files attached';
128 129 $string['nofilesavailable'] = 'No files available';
8 lib/accesslib.php
@@ -3142,8 +3142,8 @@ function get_enrolled_sql($context, $withcapability = '', $groupid = 0, $onlyact
3142 3142 }
3143 3143 }
3144 3144
3145   - $defaultuserroleid = isset($CFG->defaultuserroleid) ? $CFG->defaultuserroleid : null;
3146   - $defaultfrontpageroleid = isset($CFG->defaultfrontpageroleid) ? $CFG->defaultfrontpageroleid : null;
  3145 + $defaultuserroleid = isset($CFG->defaultuserroleid) ? $CFG->defaultuserroleid : 0;
  3146 + $defaultfrontpageroleid = isset($CFG->defaultfrontpageroleid) ? $CFG->defaultfrontpageroleid : 0;
3147 3147
3148 3148 $nobody = false;
3149 3149
@@ -4851,8 +4851,8 @@ function get_users_by_capability($context, $capability, $fields = '', $sort = ''
4851 4851 throw new coding_exception('Invalid context specified');
4852 4852 }
4853 4853
4854   - $defaultuserroleid = isset($CFG->defaultuserroleid) ? $CFG->defaultuserroleid : null;
4855   - $defaultfrontpageroleid = isset($CFG->defaultfrontpageroleid) ? $CFG->defaultfrontpageroleid : null;
  4854 + $defaultuserroleid = isset($CFG->defaultuserroleid) ? $CFG->defaultuserroleid : 0;
  4855 + $defaultfrontpageroleid = isset($CFG->defaultfrontpageroleid) ? $CFG->defaultfrontpageroleid : 0;
4856 4856
4857 4857 $ctxids = trim($context->path, '/');
4858 4858 $ctxids = str_replace('/', ',', $ctxids);
10 lib/completionlib.php
@@ -592,6 +592,9 @@ function internal_get_state($cm, $userid, $current) {
592 592 * Should be called whenever a module is 'viewed' (it is up to the module how to
593 593 * determine that). Has no effect if viewing is not set as a completion condition.
594 594 *
  595 + * Note that this function must be called before you print the page header because
  596 + * it is possible that the navigation block may depend on it. If you call it after
  597 + * printing the header, it shows a developer debug warning.
595 598 * @uses COMPLETION_VIEW_NOT_REQUIRED
596 599 * @uses COMPLETION_VIEWED
597 600 * @uses COMPLETION_COMPLETE
@@ -600,6 +603,11 @@ function internal_get_state($cm, $userid, $current) {
600 603 * @return void
601 604 */
602 605 public function set_module_viewed($cm, $userid=0) {
  606 + global $PAGE;
  607 + if ($PAGE->headerprinted) {
  608 + debugging('set_module_viewed must be called before header is printed',
  609 + DEBUG_DEVELOPER);
  610 + }
603 611 // Don't do anything if view condition is not turned on
604 612 if ($cm->completionview == COMPLETION_VIEW_NOT_REQUIRED || !$this->is_enabled($cm)) {
605 613 return;
@@ -932,6 +940,8 @@ function internal_set_data($cm, $data) {
932 940
933 941 if ($data->userid == $USER->id) {
934 942 $SESSION->completioncache[$cm->course][$cm->id] = $data;
  943 + $reset = 'reset';
  944 + get_fast_modinfo($reset);
935 945 }
936 946 }
937 947
4 lib/form/filemanager.js
@@ -636,7 +636,7 @@ M.form_filemanager.init = function(Y, options) {
636 636 dialog = Y.one('#fm-move-dlg');
637 637 }
638 638
639   - dialog.set('innerHTML', '<div class="hd">Moving</div><div class="bd"><div id="fm-move-div">'+M.str.repository.nopathselected+'</div><div id="fm-tree"></div></div>');
  639 + dialog.set('innerHTML', '<div class="hd">'+M.str.repository.moving+'</div><div class="bd"><div id="fm-move-div">'+M.str.repository.nopathselected+'</div><div id="fm-tree"></div></div>');
640 640
641 641 this.movefile_dialog = new YAHOO.widget.Dialog("fm-move-dlg", {
642 642 width : "600px",
@@ -717,7 +717,7 @@ M.form_filemanager.init = function(Y, options) {
717 717 var rootNode = treeview.getRoot();
718 718 treeview.setDynamicLoad(loadDataForNode);
719 719 treeview.removeChildren(rootNode);
720   - var textnode = {label: "Files", path: '/'};
  720 + var textnode = {label: M.str.moodle.files, path: '/'};
721 721 var tmpNode = new YAHOO.widget.TextNode(textnode, rootNode, true);
722 722 treeview.draw();
723 723 }, this, true);
11 lib/form/filemanager.php
@@ -246,7 +246,7 @@ function form_filemanager_render($options) {
246 246
247 247 $html = '';
248 248 $options = $fm->options;
249   - $straddfile = get_string('add', 'repository') . '...';
  249 + $straddfile = get_string('addfile', 'repository');
250 250 $strmakedir = get_string('makeafolder', 'moodle');
251 251 $strdownload = get_string('downloadfolder', 'repository');
252 252 $strloading = get_string('loading', 'repository');
@@ -280,9 +280,9 @@ function form_filemanager_render($options) {
280 280 <div id="filemanager-wrapper-{$client_id}" style="display:none">
281 281 <div class="fm-breadcrumb" id="fm-path-{$client_id}"></div>
282 282 <div class="filemanager-toolbar">
283   - <input type="button" class="fm-btn-add" id="btnadd-{$client_id}" onclick="return false" value=" {$straddfile}" />
284   - <input type="button" class="fm-btn-mkdir" id="btncrt-{$client_id}" onclick="return false" value=" $strmakedir" />
285   - <input type="button" class="fm-btn-download" id="btndwn-{$client_id}" onclick="return false" {$extra} value=" $strdownload" />
  283 + <input type="button" class="fm-btn-add" id="btnadd-{$client_id}" onclick="return false" value="{$straddfile}" />
  284 + <input type="button" class="fm-btn-mkdir" id="btncrt-{$client_id}" onclick="return false" value="{$strmakedir}" />
  285 + <input type="button" class="fm-btn-download" id="btndwn-{$client_id}" onclick="return false" {$extra} value="{$strdownload}" />
286 286 <span> $maxsize </span>
287 287 </div>
288 288 <div class="filemanager-container" id="filemanager-{$client_id}">
@@ -311,7 +311,8 @@ function form_filemanager_render($options) {
311 311 array('zip', 'editor'), array('unzip', 'moodle'), array('rename', 'moodle'), array('delete', 'moodle'),
312 312 array('cannotdeletefile', 'error'), array('confirmdeletefile', 'repository'),
313 313 array('nopathselected', 'repository'), array('popupblockeddownload', 'repository'),
314   - array('draftareanofiles', 'repository'), array('path', 'moodle'), array('setmainfile', 'repository')
  314 + array('draftareanofiles', 'repository'), array('path', 'moodle'), array('setmainfile', 'repository'),
  315 + array('moving', 'repository'), array('files', 'moodle')
315 316 )
316 317 );
317 318 $PAGE->requires->js_module($module);
92 lib/gradelib.php
@@ -914,6 +914,84 @@ function grade_force_site_regrading() {
914 914 }
915 915
916 916 /**
  917 + * Recover a user's grades from grade_grades_history
  918 + * @param int $userid the user ID whose grades we want to recover
  919 + * @param int $courseid the relevant course
  920 + * @return bool true if successful or false if there was an error or no grades could be recovered
  921 + */
  922 +function grade_recover_history_grades($userid, $courseid) {
  923 + global $CFG, $DB;
  924 +
  925 + if ($CFG->disablegradehistory) {
  926 + debugging('Attempting to recover grades when grade history is disabled.');
  927 + return false;
  928 + }
  929 +
  930 + //Were grades recovered? Flag to return.
  931 + $recoveredgrades = false;
  932 +
  933 + //Check the user is enrolled in this course
  934 + //Dont bother checking if they have a gradeable role. They may get one later so recover
  935 + //whatever grades they have now just in case.
  936 + $course_context = get_context_instance(CONTEXT_COURSE, $courseid);
  937 + if (!is_enrolled($course_context, $userid)) {
  938 + debugging('Attempting to recover the grades of a user who is deleted or not enrolled. Skipping recover.');
  939 + return false;
  940 + }
  941 +
  942 + //Check for existing grades for this user in this course
  943 + //Recovering grades when the user already has grades can lead to duplicate indexes and bad data
  944 + //In the future we could move the existing grades to the history table then recover the grades from before then
  945 + $sql = "SELECT gg.id
  946 + FROM {grade_grades} gg
  947 + JOIN {grade_items} gi ON gi.id = gg.itemid
  948 + WHERE gi.courseid = :courseid AND gg.userid = :userid";
  949 + $params = array('userid' => $userid, 'courseid' => $courseid);
  950 + if ($DB->record_exists_sql($sql, $params)) {
  951 + debugging('Attempting to recover the grades of a user who already has grades. Skipping recover.');
  952 + return false;
  953 + } else {
  954 + //Retrieve the user's old grades
  955 + //have history ID as first column to guarantee we a unique first column
  956 + $sql = "SELECT h.id, gi.itemtype, gi.itemmodule, gi.iteminstance as iteminstance, gi.itemnumber, h.source, h.itemid, h.userid, h.rawgrade, h.rawgrademax,
  957 + h.rawgrademin, h.rawscaleid, h.usermodified, h.finalgrade, h.hidden, h.locked, h.locktime, h.exported, h.overridden, h.excluded, h.feedback,
  958 + h.feedbackformat, h.information, h.informationformat, h.timemodified, itemcreated.tm AS timecreated
  959 + FROM {grade_grades_history} h
  960 + JOIN (SELECT itemid, MAX(id) AS id
  961 + FROM {grade_grades_history}
  962 + WHERE userid = :userid1
  963 + GROUP BY itemid) maxquery ON h.id = maxquery.id AND h.itemid = maxquery.itemid
  964 + JOIN {grade_items} gi ON gi.id = h.itemid
  965 + JOIN (SELECT itemid, MAX(timemodified) AS tm
  966 + FROM {grade_grades_history}
  967 + WHERE userid = :userid2 AND action = :insertaction
  968 + GROUP BY itemid) itemcreated ON itemcreated.itemid = h.itemid
  969 + WHERE gi.courseid = :courseid";
  970 + $params = array('userid1' => $userid, 'userid2' => $userid , 'insertaction' => GRADE_HISTORY_INSERT, 'courseid' => $courseid);
  971 + $oldgrades = $DB->get_records_sql($sql, $params);
  972 +
  973 + //now move the old grades to the grade_grades table
  974 + foreach ($oldgrades as $oldgrade) {
  975 + unset($oldgrade->id);
  976 +
  977 + $grade = new grade_grade($oldgrade, false);//2nd arg false as dont want to try and retrieve a record from the DB
  978 + $grade->insert($oldgrade->source);
  979 +
  980 + //dont include default empty grades created when activities are created
  981 + if (!is_null($oldgrade->finalgrade) || !is_null($oldgrade->feedback)) {
  982 + $recoveredgrades = true;
  983 + }
  984 + }
  985 + }
  986 +
  987 + //Some activities require manual grade synching (moving grades from the activity into the gradebook)
  988 + //If the student was deleted when synching was done they may have grades in the activity that haven't been moved across
  989 + grade_grab_course_grades($courseid, null, $userid);
  990 +
  991 + return $recoveredgrades;
  992 +}
  993 +
  994 +/**
917 995 * Updates all final grades in course.
918 996 *
919 997 * @param int $courseid
@@ -1032,14 +1110,12 @@ function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null)
1032 1110
1033 1111 /**
1034 1112 * Refetches data from all course activities
1035   - *
1036   - * @global object
1037   - * @global object
1038   - * @param int $courseid
1039   - * @param string $modname
  1113 + * @param int $courseid the course ID
  1114 + * @param string $modname limit the grade fetch to a single module type
  1115 + * @param int $userid limit the grade fetch to a single user
1040 1116 * @return void
1041 1117 */
1042   -function grade_grab_course_grades($courseid, $modname=null) {
  1118 +function grade_grab_course_grades($courseid, $modname=null, $userid=0) {
1043 1119 global $CFG, $DB;
1044 1120
1045 1121 if ($modname) {
@@ -1050,7 +1126,7 @@ function grade_grab_course_grades($courseid, $modname=null) {
1050 1126
1051 1127 if ($modinstances = $DB->get_records_sql($sql, $params)) {
1052 1128 foreach ($modinstances as $modinstance) {
1053   - grade_update_mod_grades($modinstance);
  1129 + grade_update_mod_grades($modinstance, $userid);
1054 1130 }
1055 1131 }
1056 1132 return;
@@ -1075,7 +1151,7 @@ function grade_grab_course_grades($courseid, $modname=null) {
1075 1151
1076 1152 if ($modinstances = $DB->get_records_sql($sql, $params)) {
1077 1153 foreach ($modinstances as $modinstance) {
1078   - grade_update_mod_grades($modinstance);
  1154 + grade_update_mod_grades($modinstance, $userid);
1079 1155 }
1080 1156 }
1081 1157 }
279 lib/grouplib.php
@@ -141,11 +141,10 @@ function groups_get_grouping($groupingid, $fields='*', $strictness=IGNORE_MISSIN
141 141 * @param mixed $userid optional user id or array of ids, returns only groups of the user.
142 142 * @param int $groupingid optional returns only groups in the specified grouping.
143 143 * @param string $fields
144   - * @return array|bool Returns an array of the group objects or false if no records
145   - * or an error occurred. (userid field returned if array in $userid)
  144 + * @return array Returns an array of the group objects (userid field returned if array in $userid)
146 145 */
147 146 function groups_get_all_groups($courseid, $userid=0, $groupingid=0, $fields='g.*') {
148   - global $CFG, $DB;
  147 + global $DB;
149 148
150 149 if (empty($userid)) {
151 150 $userfrom = "";
@@ -178,15 +177,12 @@ function groups_get_all_groups($courseid, $userid=0, $groupingid=0, $fields='g.*
178 177 /**
179 178 * Returns info about user's groups in course.
180 179 *
181   - * @global object
182   - * @global object
183   - * @global object
184 180 * @param int $courseid
185 181 * @param int $userid $USER if not specified
186 182 * @return array Array[groupingid][groupid] including grouping id 0 which means all groups
187 183 */
188 184 function groups_get_user_groups($courseid, $userid=0) {
189   - global $CFG, $USER, $DB;
  185 + global $USER, $DB;
190 186
191 187 if (empty($userid)) {
192 188 $userid = $USER->id;
@@ -392,15 +388,13 @@ function groups_get_activity_groupmode($cm, $course=null) {
392 388 /**
393 389 * Print group menu selector for course level.
394 390 *
395   - * @global object
396   - * @global object
397   - * @param object $course course object
398   - * @param string $urlroot return address
  391 + * @param stdClass $course course object
  392 + * @param string|moodle_url $urlroot return address
399 393 * @param boolean $return return as string instead of printing
400 394 * @return mixed void or string depending on $return param
401 395 */
402 396 function groups_print_course_menu($course, $urlroot, $return=false) {
403   - global $CFG, $USER, $SESSION, $OUTPUT;
  397 + global $USER, $OUTPUT;
404 398
405 399 if (!$groupmode = $course->groupmode) {
406 400 if ($return) {
@@ -411,44 +405,18 @@ function groups_print_course_menu($course, $urlroot, $return=false) {
411 405 }
412 406
413 407 $context = get_context_instance(CONTEXT_COURSE, $course->id);
414   - if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
415   - $allowedgroups = groups_get_all_groups($course->id, 0, $course->defaultgroupingid);
416   - // detect changes related to groups and fix active group
417   - if (!empty($SESSION->activegroup[$course->id][VISIBLEGROUPS][0])) {
418   - if (!array_key_exists($SESSION->activegroup[$course->id][VISIBLEGROUPS][0], $allowedgroups)) {
419   - // active does not exist anymore
420   - unset($SESSION->activegroup[$course->id][VISIBLEGROUPS][0]);
421   - }