Merge branch 'm27_MDL-40379_Prevent_Some_Mobile_Network_Providers_From_Modifying_Cont...
authorDan Poltawski <dan@moodle.com>
Tue, 7 Jan 2014 04:42:33 +0000 (12:42 +0800)
committerDan Poltawski <dan@moodle.com>
Tue, 7 Jan 2014 04:42:33 +0000 (12:42 +0800)
260 files changed:
admin/index.php
admin/settings/courses.php
admin/settings/development.php
admin/tool/health/index.php
backup/moodle2/backup_course_task.class.php
backup/moodle2/restore_course_task.class.php
backup/restore.php
backup/restorefile.php
backup/util/dbops/backup_controller_dbops.class.php
backup/util/helper/tests/backup_encode_content_test.php [new file with mode: 0644]
badges/action.php
badges/award.php
badges/index.php
badges/upgrade.txt
blocks/admin_bookmarks/block_admin_bookmarks.php
blocks/comments/classes/event/comment_created.php [new file with mode: 0644]
blocks/comments/classes/event/comment_deleted.php [new file with mode: 0644]
blocks/comments/tests/events_test.php [new file with mode: 0644]
blocks/recent_activity/renderer.php
blocks/site_main_menu/block_site_main_menu.php
blocks/social_activities/block_social_activities.php
blog/tests/bloglib_test.php
cache/classes/dummystore.php
cache/classes/factory.php
cache/classes/helper.php
cache/classes/store.php
cache/stores/session/lib.php
cache/stores/static/lib.php
cache/upgrade.txt
comment/lib.php
course/classes/management/helper.php
course/dndupload.js
course/dnduploadlib.php
course/externallib.php
course/format/singleactivity/lib.php
course/loginas.php
course/renderer.php
course/tests/externallib_test.php
enrol/locallib.php
grade/report/grader/lib.php
grade/tests/edittreelib_test.php
install.php
lang/en/admin.php
lang/en/backup.php
lang/en/badges.php
lang/en/install.php
lib/adminlib.php
lib/badgeslib.php
lib/behat/form_field/behat_form_checkbox.php
lib/classes/component.php
lib/classes/event/assessable_uploaded.php
lib/classes/event/blog_association_created.php
lib/classes/event/blog_comment_created.php [new file with mode: 0644]
lib/classes/event/blog_comment_deleted.php [new file with mode: 0644]
lib/classes/event/blog_entries_viewed.php
lib/classes/event/comment_created.php
lib/classes/event/comment_deleted.php
lib/classes/event/comments_viewed.php
lib/classes/event/content_viewed.php
lib/classes/event/course_category_deleted.php
lib/classes/event/course_content_deleted.php
lib/classes/event/course_created.php
lib/classes/event/course_deleted.php
lib/classes/event/course_module_created.php
lib/classes/event/course_module_deleted.php
lib/classes/event/course_module_updated.php
lib/classes/event/course_reset_ended.php
lib/classes/event/course_reset_started.php
lib/classes/event/course_restored.php
lib/classes/event/course_section_updated.php
lib/classes/event/course_updated.php
lib/classes/event/group_member_added.php
lib/classes/event/note_created.php
lib/classes/event/note_deleted.php
lib/classes/event/note_updated.php
lib/classes/event/notes_viewed.php
lib/classes/event/role_assigned.php
lib/classes/event/role_deleted.php
lib/classes/event/role_unassigned.php
lib/classes/event/user_deleted.php
lib/classes/event/user_enrolment_created.php
lib/classes/event/user_enrolment_deleted.php
lib/classes/event/user_enrolment_updated.php
lib/classes/event/user_list_viewed.php
lib/classes/event/user_loggedin.php
lib/classes/event/user_loggedinas.php
lib/classes/event/user_loggedout.php
lib/classes/event/user_profile_viewed.php
lib/classes/event/webservice_function_called.php
lib/classes/event/webservice_login_failed.php
lib/classes/event/webservice_service_created.php
lib/classes/event/webservice_token_created.php
lib/configonlylib.php
lib/coursecatlib.php
lib/db/upgrade.php
lib/editor/tinymce/plugins/managefiles/lib.php
lib/filelib.php
lib/filestorage/mbz_packer.php
lib/filestorage/tests/mbz_packer_test.php
lib/filestorage/tests/tgz_packer_test.php
lib/filestorage/tgz_packer.php
lib/htaccess
lib/modinfolib.php
lib/navigationlib.php
lib/outputrequirementslib.php
lib/rsslib.php
lib/setup.php
lib/setuplib.php
lib/tests/admintree_test.php
lib/tests/modinfolib_test.php
lib/tests/weblib_test.php
lib/thirdpartylibs.xml
lib/upgrade.txt
lib/weblib.php
lib/yui/build/moodle-core-blocks/moodle-core-blocks-debug.js
lib/yui/build/moodle-core-blocks/moodle-core-blocks-min.js
lib/yui/build/moodle-core-blocks/moodle-core-blocks.js
lib/yui/build/moodle-core-tooltip/moodle-core-tooltip-debug.js
lib/yui/build/moodle-core-tooltip/moodle-core-tooltip-min.js
lib/yui/build/moodle-core-tooltip/moodle-core-tooltip.js
lib/yui/src/blocks/js/blockregion.js
lib/yui/src/tooltip/js/tooltip.js
lib/yui/src/tooltip/meta/tooltip.json
lib/yuilib/gallery/gallery-sm-treeview-sortable/gallery-sm-treeview-sortable-debug.js [moved from mod/scorm/yui/src/treeview/js/gallery-sm-treeview-sortable-debug.js with 89% similarity]
lib/yuilib/gallery/gallery-sm-treeview-sortable/gallery-sm-treeview-sortable-min.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview-sortable/gallery-sm-treeview-sortable.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates-debug.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates-min.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview/assets/gallery-sm-treeview-core.css [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/moodle-mod_scorm-treeview-core.css with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/folder.png [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/folder.png with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/folder@2x.png [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/folder@2x.png with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/gallery-sm-treeview-skin.css [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/moodle-mod_scorm-treeview-skin.css with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/gallery-sm-treeview.css [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/moodle-mod_scorm-treeview.css with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/item.png [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/item.png with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/item@2x.png [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/item@2x.png with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/gallery-sm-treeview-debug.js [moved from mod/scorm/yui/src/treeview/js/gallery-sm-treeview-debug.js with 95% similarity]
lib/yuilib/gallery/gallery-sm-treeview/gallery-sm-treeview-min.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview/gallery-sm-treeview.js [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/moodle-mod_scorm-treeview-sortable-debug.js with 94% similarity]
lib/yuilib/readme_moodle.txt
mod/assign/classes/event/assessable_submitted.php
mod/assign/classes/event/marker_updated.php
mod/assign/classes/event/submission_status_updated.php
mod/assign/classes/event/workflow_state_updated.php
mod/assign/db/access.php
mod/assign/feedback/comments/locallib.php
mod/assign/feedback/editpdf/lang/en/assignfeedback_editpdf.php
mod/assign/feedback/editpdf/locallib.php
mod/assign/feedback/editpdf/settings.php
mod/assign/gradingtable.php
mod/assign/lang/en/assign.php
mod/assign/lib.php
mod/assign/locallib.php
mod/assign/submission/comments/classes/event/comment_created.php [new file with mode: 0644]
mod/assign/submission/comments/classes/event/comment_deleted.php [new file with mode: 0644]
mod/assign/submission/comments/lib.php
mod/assign/submission/comments/tests/events_test.php [new file with mode: 0644]
mod/assign/submission/file/classes/event/assessable_uploaded.php
mod/assign/submission/onlinetext/classes/event/assessable_uploaded.php
mod/assign/tests/locallib_test.php
mod/assign/version.php
mod/assignment/type/online/assignment.class.php
mod/assignment/type/online/classes/event/assessable_uploaded.php
mod/assignment/type/upload/classes/event/assessable_submitted.php
mod/assignment/type/upload/classes/event/assessable_uploaded.php
mod/chat/chatd.php
mod/chat/classes/event/sessions_viewed.php
mod/choice/classes/event/answer_submitted.php
mod/choice/classes/event/answer_updated.php
mod/choice/classes/event/report_viewed.php
mod/data/classes/event/comment_created.php [new file with mode: 0644]
mod/data/classes/event/comment_deleted.php [new file with mode: 0644]
mod/data/tests/lib_test.php
mod/feedback/classes/event/course_module_viewed.php
mod/feedback/classes/event/response_deleted.php
mod/feedback/classes/event/response_submitted.php
mod/folder/classes/event/course_module_instance_list_viewed.php [new file with mode: 0644]
mod/folder/classes/event/course_module_viewed.php [new file with mode: 0644]
mod/folder/classes/event/folder_updated.php [new file with mode: 0644]
mod/folder/edit.php
mod/folder/index.php
mod/folder/lang/en/folder.php
mod/folder/lib.php
mod/folder/tests/events_test.php [new file with mode: 0644]
mod/folder/view.php
mod/forum/classes/event/assessable_uploaded.php
mod/forum/lib.php
mod/forum/post.php
mod/glossary/classes/event/comment_created.php [new file with mode: 0644]
mod/glossary/classes/event/comment_deleted.php [new file with mode: 0644]
mod/glossary/tests/events_test.php [new file with mode: 0644]
mod/lesson/classes/event/course_module_instance_list_viewed.php [new file with mode: 0644]
mod/lesson/classes/event/course_module_viewed.php [new file with mode: 0644]
mod/lesson/classes/event/essay_attempt_viewed.php [new file with mode: 0644]
mod/lesson/classes/event/highscore_added.php [new file with mode: 0644]
mod/lesson/classes/event/highscores_viewed.php [new file with mode: 0644]
mod/lesson/classes/event/lesson_ended.php [new file with mode: 0644]
mod/lesson/classes/event/lesson_started.php [new file with mode: 0644]
mod/lesson/classes/file_info.php [new file with mode: 0644]
mod/lesson/essay.php
mod/lesson/highscores.php
mod/lesson/index.php
mod/lesson/lang/en/lesson.php
mod/lesson/lib.php
mod/lesson/locallib.php
mod/lesson/tests/events_test.php [new file with mode: 0644]
mod/lesson/view.php
mod/lti/classes/event/unknown_service_api_called.php
mod/quiz/classes/event/attempt_abandoned.php
mod/quiz/classes/event/attempt_becameoverdue.php
mod/quiz/classes/event/attempt_submitted.php
mod/resource/lib.php
mod/scorm/locallib.php
mod/scorm/module.js
mod/scorm/thirdpartylibs.xml [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/moodle-mod_scorm-treeview-sortable-min.js [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/moodle-mod_scorm-treeview-sortable.js [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/moodle-mod_scorm-treeview-core.css [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/folder.png [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/folder@2x.png [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/item.png [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/item@2x.png [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/moodle-mod_scorm-treeview-skin.css [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/moodle-mod_scorm-treeview.css [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/moodle-mod_scorm-treeview-debug.js [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/moodle-mod_scorm-treeview-min.js [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/moodle-mod_scorm-treeview.js [deleted file]
mod/scorm/yui/src/treeview/assets/moodle-mod_scorm-treeview-core.css [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/folder.png [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/folder@2x.png [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/item.png [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/item@2x.png [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/moodle-mod_scorm-treeview-skin.css [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/moodle-mod_scorm-treeview.css [deleted file]
mod/scorm/yui/src/treeview/build.json [deleted file]
mod/scorm/yui/src/treeview/js/treeview-sortable.js [deleted file]
mod/scorm/yui/src/treeview/js/treeview.js [deleted file]
mod/scorm/yui/src/treeview/meta/sm-treeview.json [deleted file]
mod/scorm/yui/src/treeview/readme_moodle.txt [deleted file]
mod/wiki/classes/event/comment_created.php
mod/wiki/classes/event/comment_deleted.php
mod/wiki/classes/event/comments_viewed.php
mod/wiki/classes/event/page_deleted.php
mod/wiki/classes/event/page_diff_viewed.php
mod/wiki/classes/event/page_locks_deleted.php
mod/wiki/classes/event/page_map_viewed.php
mod/wiki/classes/event/page_updated.php
mod/wiki/classes/event/page_version_deleted.php
mod/wiki/classes/event/page_version_restored.php
mod/wiki/classes/event/page_version_viewed.php
mod/workshop/classes/event/assessable_uploaded.php
report/log/classes/event/content_viewed.php
report/loglive/classes/event/content_viewed.php
report/outline/classes/event/content_viewed.php
report/participation/classes/event/content_viewed.php
report/stats/classes/event/content_viewed.php
theme/yui_combo.php
theme/yui_image.php
user/profile/index.php
version.php

index e42687a..3cdb0eb 100644 (file)
@@ -119,10 +119,6 @@ if (ini_get_bool('session.auto_start')) {
     print_error('phpvaroff', 'debug', '', (object)array('name'=>'session.auto_start', 'link'=>$documentationlink));
 }
 
-if (ini_get_bool('magic_quotes_runtime')) {
-    print_error('phpvaroff', 'debug', '', (object)array('name'=>'magic_quotes_runtime', 'link'=>$documentationlink));
-}
-
 if (!ini_get_bool('file_uploads')) {
     print_error('phpvaron', 'debug', '', (object)array('name'=>'file_uploads', 'link'=>$documentationlink));
 }
index d69b8e2..f9afd0a 100644 (file)
@@ -26,7 +26,8 @@ $capabilities = array(
     'moodle/backup:backupcourse',
     'moodle/category:manage',
     'moodle/course:create',
-    'moodle/site:approvecourse'
+    'moodle/site:approvecourse',
+    'moodle/restore:restorecourse'
 );
 if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
     // Speedup for non-admins, add all caps used on this page.
@@ -42,6 +43,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
             array('moodle/category:manage')
         )
     );
+    $ADMIN->add('courses',
+        new admin_externalpage('restorecourse', new lang_string('restorecourse', 'admin'),
+            new moodle_url('/backup/restorefile.php', array('contextid' => context_system::instance()->id)),
+            array('moodle/course:create')
+        )
+    );
 
     // Course Default Settings Page.
     // NOTE: these settings must be applied after all other settings because they depend on them.
index a1ad6e0..b99d519 100644 (file)
@@ -27,9 +27,6 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $temp->add(new admin_setting_configcheckbox('enabletgzbackups',
             new lang_string('enabletgzbackups', 'admin'),
             new lang_string('enabletgzbackups_desc', 'admin'), 0));
-    $temp->add(new admin_setting_php_extension_enabled('zlibenabled',
-            get_string('zlibenabled', 'admin'),
-            get_string('enabletgzbackups_nozlib', 'admin'), 'zlib'));
 
     $ADMIN->add('experimental', $temp);
 
index 3966865..f0fe6c8 100644 (file)
@@ -240,25 +240,6 @@ class problem_000005 extends problem_base {
     }
 }
 
-class problem_000006 extends problem_base {
-    function title() {
-        return 'PHP: magic_quotes_runtime is enabled';
-    }
-    function exists() {
-        return (ini_get_bool('magic_quotes_runtime'));
-    }
-    function severity() {
-        return SEVERITY_SIGNIFICANT;
-    }
-    function description() {
-        return 'Your PHP configuration includes an enabled setting, magic_quotes_runtime, that <strong>must be disabled</strong> in order for Moodle to work correctly. Notable symptoms arising from this misconfiguration include strange display errors whenever a text field that includes single or double quotes is processed.';
-    }
-    function solution() {
-        global $CFG;
-        return '<p>There are two ways you can solve this problem:</p><ol><li>If you have access to your main <strong>php.ini</strong> file, then find the line that looks like this: <pre>magic_quotes_runtime = On</pre> and change it to <pre>magic_quotes_runtime = Off</pre> and then restart your web server. Be warned that this, as any other PHP setting change, might affect other web applications running on the server.</li><li>Finally, you may be able to change this setting just for your site by creating or editing the file <strong>'.$CFG->dirroot.'/.htaccess</strong> to contain this line: <pre>php_value magic_quotes_runtime "Off"</pre></li></ol>';
-    }
-}
-
 class problem_000007 extends problem_base {
     function title() {
         return 'PHP: file_uploads is disabled';
index 7e37f99..11f245f 100644 (file)
@@ -131,20 +131,38 @@ class backup_course_task extends backup_task {
     /**
      * Code the transformations to perform in the course in
      * order to get transportable (encoded) links
+     * @param string $content content in which to encode links.
+     * @return string content with links encoded.
      */
     static public function encode_content_links($content) {
-        global $CFG;
-
-        $base = preg_quote($CFG->wwwroot, '/');
 
         // Link to the course main page (it also covers "&topic=xx" and "&week=xx"
-        // because they don't become transformed (section number) in backup/restore
-        $search = '/(' . $base . '\/course\/view.php\?id\=)([0-9]+)/';
-        $content= preg_replace($search, '$@COURSEVIEWBYID*$2@$', $content);
+        // because they don't become transformed (section number) in backup/restore.
+        $content = self::encode_links_helper($content, 'COURSEVIEWBYID',       '/course/view.php?id=');
+
+        // A few other key course links.
+        $content = self::encode_links_helper($content, 'GRADEINDEXBYID',       '/grade/index.php?id=');
+        $content = self::encode_links_helper($content, 'GRADEREPORTINDEXBYID', '/grade/report/index.php?id=');
+        $content = self::encode_links_helper($content, 'BADGESVIEWBYID',       '/badges/view.php?type=2&id=');
+        $content = self::encode_links_helper($content, 'USERINDEXVIEWBYID',    '/user/index.php?id=');
 
         return $content;
     }
 
+    /**
+     * Helper method, used by encode_content_links.
+     * @param string $content content in which to encode links.
+     * @param unknown_type $name the name of this type of encoded link.
+     * @param unknown_type $path the path that identifies this type of link, up
+     *      to the ?paramname= bit.
+     * @return string content with one type of link encoded.
+     */
+    static private function encode_links_helper($content, $name, $path) {
+        global $CFG;
+        $base = preg_quote($CFG->wwwroot . $path, '/');
+        return preg_replace('/(' . $base . ')([0-9]+)/', '$@' . $name . '*$2@$', $content);
+    }
+
 // Protected API starts here
 
     /**
index 74bfef4..e9058b8 100644 (file)
@@ -135,10 +135,17 @@ class restore_course_task extends restore_task {
     static public function define_decode_rules() {
         $rules = array();
 
-        $rules[] = new restore_decode_rule('COURSEVIEWBYID', '/course/view.php?id=$1', 'course');
+        // Link to the course main page (it also covers "&topic=xx" and "&week=xx"
+        // because they don't become transformed (section number) in backup/restore.
+        $rules[] = new restore_decode_rule('COURSEVIEWBYID',       '/course/view.php?id=$1',        'course');
 
-        return $rules;
+        // A few other key course links.
+        $rules[] = new restore_decode_rule('GRADEINDEXBYID',       '/grade/index.php?id=$1',        'course');
+        $rules[] = new restore_decode_rule('GRADEREPORTINDEXBYID', '/grade/report/index.php?id=$1', 'course');
+        $rules[] = new restore_decode_rule('BADGESVIEWBYID',       '/badges/view.php?type=2&id=$1', 'course');
+        $rules[] = new restore_decode_rule('USERINDEXVIEWBYID',    '/user/index.php?id=$1',         'course');
 
+        return $rules;
     }
 
 // Protected API starts here
index 6e19ef9..9612163 100644 (file)
@@ -17,9 +17,17 @@ $PAGE->set_pagelayout('standard');
 require_login($course, null, $cm);
 require_capability('moodle/restore:restorecourse', $context);
 
+if (is_null($course)) {
+    $coursefullname = $SITE->fullname;
+    $courseshortname = $SITE->shortname;
+} else {
+    $coursefullname = $course->fullname;
+    $courseshortname = $course->shortname;
+}
+
 // Show page header.
-$PAGE->set_title($course->shortname . ': ' . get_string('restore'));
-$PAGE->set_heading($course->fullname);
+$PAGE->set_title($courseshortname . ': ' . get_string('restore'));
+$PAGE->set_heading($coursefullname);
 
 $renderer = $PAGE->get_renderer('core','backup');
 echo $OUTPUT->header();
index 1d12d0d..411aeb6 100644 (file)
@@ -61,6 +61,14 @@ switch ($context->contextlevel) {
 require_login($course, false, $cm);
 require_capability('moodle/restore:restorecourse', $context);
 
+if (is_null($course)) {
+    $courseid = 0;
+    $coursefullname = $SITE->fullname;
+} else {
+    $courseid = $course->id;
+    $coursefullname = $course->fullname;
+}
+
 $browser = get_file_browser();
 
 // check if tmp dir exists
@@ -83,7 +91,7 @@ if ($action == 'choosebackupfile') {
                     'pathnamehash' => $file->get_pathnamehash(), 'contenthash' => $file->get_contenthash()));
         } else {
             // If it's some weird other kind of file then use old code.
-            $filename = restore_controller::get_tempdir_name($course->id, $USER->id);
+            $filename = restore_controller::get_tempdir_name($courseid, $USER->id);
             $pathname = $tmpdir . '/' . $filename;
             $fileinfo->copy_to_pathname($pathname);
             $restore_url = new moodle_url('/backup/restore.php', array(
@@ -98,14 +106,14 @@ if ($action == 'choosebackupfile') {
 
 $PAGE->set_url($url);
 $PAGE->set_context($context);
-$PAGE->set_title(get_string('course') . ': ' . $course->fullname);
+$PAGE->set_title(get_string('course') . ': ' . $coursefullname);
 $PAGE->set_heading($heading);
 $PAGE->set_pagelayout('admin');
 
 $form = new course_restore_form(null, array('contextid'=>$contextid));
 $data = $form->get_data();
 if ($data && has_capability('moodle/restore:uploadfile', $context)) {
-    $filename = restore_controller::get_tempdir_name($course->id, $USER->id);
+    $filename = restore_controller::get_tempdir_name($courseid, $USER->id);
     $pathname = $tmpdir . '/' . $filename;
     $form->save_file('backupfile', $pathname);
     $restore_url = new moodle_url('/backup/restore.php', array('contextid'=>$contextid, 'filename'=>$filename));
index 6d066b4..d9715d1 100644 (file)
@@ -175,11 +175,7 @@ abstract class backup_controller_dbops extends backup_dbops {
     public static function decode_backup_temp_info($info) {
         // We encode all data except null.
         if ($info != null) {
-            if (extension_loaded('zlib')) {
-                return unserialize(gzuncompress(base64_decode($info)));
-            } else {
-                return unserialize(base64_decode($info));
-            }
+            return unserialize(gzuncompress(base64_decode($info)));
         }
         return $info;
     }
@@ -195,11 +191,7 @@ abstract class backup_controller_dbops extends backup_dbops {
         if ($info != null) {
             // We compress if possible. It reduces db, network and memory storage. The saving is greater than CPU compression cost.
             // Compression level 1 is chosen has it produces good compression with the smallest possible overhead, see MDL-40618.
-            if (extension_loaded('zlib')) {
-                return base64_encode(gzcompress(serialize($info), 1));
-            } else {
-                return base64_encode(serialize($info));
-            }
+            return base64_encode(gzcompress(serialize($info), 1));
         }
         return $info;
     }
diff --git a/backup/util/helper/tests/backup_encode_content_test.php b/backup/util/helper/tests/backup_encode_content_test.php
new file mode 100644 (file)
index 0000000..26299d9
--- /dev/null
@@ -0,0 +1,56 @@
+<?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/>.
+
+/**
+ * @package    core_backup
+ * @category   phpunit
+ * @copyright  2013 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+
+global $CFG;
+require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
+require_once($CFG->dirroot . '/backup/moodle2/backup_course_task.class.php');
+
+
+
+/**
+ * Tests for encoding content links in backup_course_task.
+ *
+ * The code that this tests is acutally in backup/moodle2/backup_course_task.class.php,
+ * but there is no place for unit tests near there, and perhaps one day it will
+ * be refactored so it becomes more generic.
+ */
+class backup_course_task_testcase extends basic_testcase {
+
+    /**
+     * Test the encode_content_links method for course.
+     */
+    public function test_course_encode_content_links() {
+        global $CFG;
+        $encoded = backup_course_task::encode_content_links(
+                $CFG->wwwroot . '/course/view.php?id=123, ' .
+                $CFG->wwwroot . '/grade/index.php?id=123, ' .
+                $CFG->wwwroot . '/grade/report/index.php?id=123, ' .
+                $CFG->wwwroot . '/badges/view.php?type=2&id=123 and ' .
+                $CFG->wwwroot . '/user/index.php?id=123.');
+        $this->assertEquals('$@COURSEVIEWBYID*123@$, $@GRADEINDEXBYID*123@$, ' .
+                '$@GRADEREPORTINDEXBYID*123@$, $@BADGESVIEWBYID*123@$ and $@USERINDEXVIEWBYID*123@$.', $encoded);
+    }
+}
index 929d9a0..31843a2 100644 (file)
@@ -29,7 +29,6 @@ require_once($CFG->libdir . '/badgeslib.php');
 
 $badgeid = required_param('id', PARAM_INT);
 $copy = optional_param('copy', 0, PARAM_BOOL);
-$delete    = optional_param('delete', 0, PARAM_BOOL);
 $activate = optional_param('activate', 0, PARAM_BOOL);
 $deactivate = optional_param('lock', 0, PARAM_BOOL);
 $confirm   = optional_param('confirm', 0, PARAM_BOOL);
@@ -61,38 +60,6 @@ if ($return !== 0) {
 }
 $returnurl->remove_params('awards');
 
-if ($delete) {
-    require_capability('moodle/badges:deletebadge', $context);
-
-    $PAGE->url->param('delete', 1);
-    if ($confirm) {
-        require_sesskey();
-        $badge->delete();
-        redirect(new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid)));
-    }
-
-    $strheading = get_string('delbadge', 'badges');
-    $PAGE->navbar->add($strheading);
-    $PAGE->set_title($strheading);
-    $PAGE->set_heading($badge->name);
-    echo $OUTPUT->header();
-    echo $OUTPUT->heading($strheading);
-
-    $urlparams = array(
-        'id' => $badge->id,
-        'delete' => 1,
-        'confirm' => 1,
-        'sesskey' => sesskey()
-    );
-    $continue = new moodle_url('/badges/action.php', $urlparams);
-    $cancel = new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid));
-
-    $message = get_string('delconfirm', 'badges', $badge->name);
-    echo $OUTPUT->confirm($message, $continue, $cancel);
-    echo $OUTPUT->footer();
-    die;
-}
-
 if ($copy) {
     require_sesskey();
     require_capability('moodle/badges:createbadge', $context);
index 9c3db8c..124e178 100644 (file)
@@ -109,7 +109,7 @@ if (count($acceptedroles) > 1) {
             $pageurl = new moodle_url('/badges/award.php', array('id' => $badgeid));
             $issuerrole = new stdClass();
             $issuerrole->roleid = $role;
-            $roleselect = get_string('selectaward', 'badges') . $OUTPUT->single_select(new moodle_url($pageurl), 'role', $select, $role);
+            $roleselect = get_string('selectaward', 'badges') . $OUTPUT->single_select(new moodle_url($pageurl), 'role', $select, $role, null);
         }
     } else {
         echo $OUTPUT->header();
index 6c73990..ecc0d4f 100644 (file)
@@ -30,12 +30,12 @@ require_once($CFG->libdir . '/badgeslib.php');
 $type       = required_param('type', PARAM_INT);
 $courseid   = optional_param('id', 0, PARAM_INT);
 $page       = optional_param('page', 0, PARAM_INT);
-$activate   = optional_param('activate', 0, PARAM_INT);
 $deactivate = optional_param('lock', 0, PARAM_INT);
 $sortby     = optional_param('sort', 'name', PARAM_ALPHA);
 $sorthow    = optional_param('dir', 'ASC', PARAM_ALPHA);
 $confirm    = optional_param('confirm', false, PARAM_BOOL);
 $delete     = optional_param('delete', 0, PARAM_INT);
+$archive    = optional_param('archive', 0, PARAM_INT);
 $msg        = optional_param('msg', '', PARAM_TEXT);
 
 if (!in_array($sortby, array('name', 'status'))) {
@@ -107,20 +107,34 @@ $PAGE->requires->js('/badges/backpack.js');
 $PAGE->requires->js_init_call('check_site_access', null, false);
 $output = $PAGE->get_renderer('core', 'badges');
 
-if ($delete && has_capability('moodle/badges:deletebadge', $PAGE->context)) {
-    $badge = new badge($delete);
+if (($delete || $archive) && has_capability('moodle/badges:deletebadge', $PAGE->context)) {
+    $badgeid = ($archive != 0) ? $archive : $delete;
+    $badge = new badge($badgeid);
     if (!$confirm) {
         echo $output->header();
-        echo $output->confirm(
-                    get_string('delconfirm', 'badges', $badge->name),
-                    new moodle_url($PAGE->url, array('delete' => $badge->id, 'confirm' => 1)),
-                    $returnurl
-                );
+        // Archive this badge?
+        echo $output->heading(get_string('archivebadge', 'badges', $badge->name));
+        $archivebutton = $output->single_button(
+                            new moodle_url($PAGE->url, array('archive' => $badge->id, 'confirm' => 1)),
+                            get_string('archiveconfirm', 'badges'));
+        echo $output->box(get_string('archivehelp', 'badges') . $archivebutton, 'generalbox');
+
+        // Delete this badge?
+        echo $output->heading(get_string('delbadge', 'badges', $badge->name));
+        $deletebutton = $output->single_button(
+                            new moodle_url($PAGE->url, array('delete' => $badge->id, 'confirm' => 1)),
+                            get_string('delconfirm', 'badges'));
+        echo $output->box(get_string('deletehelp', 'badges') . $deletebutton, 'generalbox');
+
+        // Go back.
+        echo $output->action_link($returnurl, get_string('cancel'));
+
         echo $output->footer();
         die();
     } else {
         require_sesskey();
-        $badge->delete();
+        $archiveonly = ($archive != 0) ? true : false;
+        $badge->delete($archiveonly);
         redirect($returnurl);
     }
 }
index 1a48ffd..bab46ee 100644 (file)
@@ -7,6 +7,9 @@ information provided here is intended especially for developers.
   in all criteria classes. This method returns an array consisting of SQL JOIN statement, WHERE conditions,
   and any parameters that might be required. The results are used in lib/badgeslib.php in review_all_criteria()
   to reduce to the minimum the number of users to review and award badges.
-
 * New optional parameter $filtered in review() allows to indicate that some expensive checks can be skipped
   if the list of users has been initially filtered based on met criteria.
+* New optional parameter $archive in delete() in badge class in badgeslib.php
+  allows to indicate that a badge should be archived instead of fully deleted.
+  If this parameter is set to FALSE, a badge will all its information, criteria,
+  and awards will be removed from the database.
index 84303c3..09071ee 100644 (file)
@@ -107,7 +107,7 @@ class block_admin_bookmarks extends block_base {
 
         $this->content->footer = '';
         $this->page->settingsnav->initialise();
-        $node = $this->page->settingsnav->get('root', navigation_node::TYPE_SETTING);
+        $node = $this->page->settingsnav->get('root', navigation_node::TYPE_SITE_ADMIN);
         if (!$node || !$node->contains_active_node()) {
             return $this->content;
         }
diff --git a/blocks/comments/classes/event/comment_created.php b/blocks/comments/classes/event/comment_created.php
new file mode 100644 (file)
index 0000000..db96870
--- /dev/null
@@ -0,0 +1,37 @@
+<?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/>.
+
+/**
+ * block_comments comment created event.
+ *
+ * @package    block_comments
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_comments\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * block_comments comment created event.
+ *
+ * @package    block_comments
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class comment_created extends \core\event\comment_created {
+    // No need to override any method.
+}
diff --git a/blocks/comments/classes/event/comment_deleted.php b/blocks/comments/classes/event/comment_deleted.php
new file mode 100644 (file)
index 0000000..a347c0b
--- /dev/null
@@ -0,0 +1,37 @@
+<?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/>.
+
+/**
+ * block_comments comment deleted event.
+ *
+ * @package    block_comments
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_comments\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * block_comments comment deleted event.
+ *
+ * @package    block_comments
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class comment_deleted extends \core\event\comment_deleted {
+    // No need to override any method.
+}
diff --git a/blocks/comments/tests/events_test.php b/blocks/comments/tests/events_test.php
new file mode 100644 (file)
index 0000000..7cb8e88
--- /dev/null
@@ -0,0 +1,182 @@
+<?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/>.
+
+/**
+ * Events tests.
+ *
+ * @package    block_comments
+ * @category   test
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Events tests class.
+ *
+ * @package    block_comments
+ * @category   test
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_comments_events_testcase extends advanced_testcase {
+    /** @var stdClass Keeps course object */
+    private $course;
+
+    /** @var stdClass Keeps wiki object */
+    private $wiki;
+
+    /**
+     * Setup test data.
+     */
+    public function setUp() {
+        $this->resetAfterTest();
+        $this->setAdminUser();
+
+        // Create course and wiki.
+        $this->course = $this->getDataGenerator()->create_course();
+        $this->wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $this->course->id));
+    }
+
+    /**
+     * Test comment_created event.
+     */
+    public function test_comment_created() {
+        global $CFG;
+
+        require_once($CFG->dirroot . '/comment/lib.php');
+
+        // Comment on course page.
+        $context = context_course::instance($this->course->id);
+        $args = new stdClass;
+        $args->context = $context;
+        $args->course = $this->course;
+        $args->area = 'page_comments';
+        $args->itemid = 0;
+        $args->component = 'block_comments';
+        $args->linktext = get_string('showcomments');
+        $args->notoggle = true;
+        $args->autostart = true;
+        $args->displaycancel = false;
+        $comment = new comment($args);
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $comment->add('New comment');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\block_comments\event\comment_created', $event);
+        $this->assertEquals($context, $event->get_context());
+        $url = new moodle_url('/course/view.php', array('id' => $this->course->id));
+        $this->assertEquals($url, $event->get_url());
+
+        // Comments when block is on module (wiki) page.
+        $context = context_module::instance($this->wiki->id);
+        $args = new stdClass;
+        $args->context   = $context;
+        $args->course    = $this->course;
+        $args->area      = 'page_comments';
+        $args->itemid    = 0;
+        $args->component = 'block_comments';
+        $args->linktext  = get_string('showcomments');
+        $args->notoggle  = true;
+        $args->autostart = true;
+        $args->displaycancel = false;
+        $comment = new comment($args);
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $comment->add('New comment 1');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\block_comments\event\comment_created', $event);
+        $this->assertEquals($context, $event->get_context());
+        $url = new moodle_url('/mod/wiki/view.php', array('id' => $this->wiki->id));
+        $this->assertEquals($url, $event->get_url());
+    }
+
+    /**
+     * Test comment_deleted event.
+     */
+    public function test_comment_deleted() {
+        global $CFG;
+
+        require_once($CFG->dirroot . '/comment/lib.php');
+
+        // Comment on course page.
+        $context = context_course::instance($this->course->id);
+        $args = new stdClass;
+        $args->context   = $context;
+        $args->course    = $this->course;
+        $args->area      = 'page_comments';
+        $args->itemid    = 0;
+        $args->component = 'block_comments';
+        $args->linktext  = get_string('showcomments');
+        $args->notoggle  = true;
+        $args->autostart = true;
+        $args->displaycancel = false;
+        $comment = new comment($args);
+        $newcomment = $comment->add('New comment');
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $comment->delete($newcomment->id);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\block_comments\event\comment_deleted', $event);
+        $this->assertEquals($context, $event->get_context());
+        $url = new moodle_url('/course/view.php', array('id' => $this->course->id));
+        $this->assertEquals($url, $event->get_url());
+
+        // Comments when block is on module (wiki) page.
+        $context = context_module::instance($this->wiki->id);
+        $args = new stdClass;
+        $args->context   = $context;
+        $args->course    = $this->course;
+        $args->area      = 'page_comments';
+        $args->itemid    = 0;
+        $args->component = 'block_comments';
+        $args->linktext  = get_string('showcomments');
+        $args->notoggle  = true;
+        $args->autostart = true;
+        $args->displaycancel = false;
+        $comment = new comment($args);
+        $newcomment = $comment->add('New comment 1');
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $comment->delete($newcomment->id);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\block_comments\event\comment_deleted', $event);
+        $this->assertEquals($context, $event->get_context());
+        $url = new moodle_url('/mod/wiki/view.php', array('id' => $this->wiki->id));
+        $this->assertEquals($url, $event->get_url());
+    }
+}
index b77f584..2e96eeb 100644 (file)
@@ -114,11 +114,11 @@ class block_recent_activity_renderer extends plugin_renderer_base {
                 break;
             case 'add mod':
                 $text = get_string('added', 'moodle', $cm->modfullname). '<br />'.
-                    html_writer::link($cm->get_url(), format_string($cm->name, true));
+                    html_writer::link($cm->url, format_string($cm->name, true));
                 break;
             case 'update mod':
                 $text = get_string('updated', 'moodle', $cm->modfullname). '<br />'.
-                    html_writer::link($cm->get_url(), format_string($cm->name, true));
+                    html_writer::link($cm->url, format_string($cm->name, true));
                 break;
             default:
                 return '';
index 762bb64..3aaa309 100644 (file)
@@ -44,7 +44,7 @@ class block_site_main_menu extends block_list {
                     $content = $cm->get_formatted_content(array('overflowdiv' => true, 'noclean' => true));
                     $instancename = $cm->get_formatted_name();
 
-                    if (!($url = $cm->get_url())) {
+                    if (!($url = $cm->url)) {
                         $this->content->items[] = $content;
                         $this->content->icons[] = '';
                     } else {
@@ -123,7 +123,7 @@ class block_site_main_menu extends block_list {
                     $instancename = $mod->get_formatted_name();
                     $linkcss = $mod->visible ? '' : ' class="dimmed" ';
 
-                    if (!($url = $mod->get_url())) {
+                    if (!($url = $mod->url)) {
                         $this->content->items[] = $content . $editbuttons;
                         $this->content->icons[] = '';
                     } else {
index b802221..96f7a90 100644 (file)
@@ -46,7 +46,7 @@ class block_social_activities extends block_list {
                     $content = $cm->get_formatted_content(array('overflowdiv' => true, 'noclean' => true));
                     $instancename = $cm->get_formatted_name();
 
-                    if (!($url = $cm->get_url())) {
+                    if (!($url = $cm->url)) {
                         $this->content->items[] = $content;
                         $this->content->icons[] = '';
                     } else {
@@ -110,7 +110,7 @@ class block_social_activities extends block_list {
 
                     $linkcss = $mod->visible ? '' : ' class="dimmed" ';
 
-                    if (!($url = $mod->get_url())) {
+                    if (!($url = $mod->url)) {
                         $this->content->items[] = $content . $editbuttons;
                         $this->content->icons[] = '';
                     } else {
index 47c8a29..0109fd4 100644 (file)
@@ -362,7 +362,7 @@ class core_bloglib_testcase extends advanced_testcase {
     public function test_blog_entries_viewed_event() {
 
         $this->setAdminUser();
-        $this->resetAfterTest();
+
         $other = array('entryid' => $this->postid, 'tagid' => $this->tagid, 'userid' => $this->userid, 'modid' => $this->cmid,
                        'groupid' => $this->groupid, 'courseid' => $this->courseid, 'search' => 'search', 'fromstart' => 2);
 
@@ -382,5 +382,76 @@ class core_bloglib_testcase extends advanced_testcase {
         $arr = array(SITEID, 'blog', 'view', $url2->out(), 'view blog entry');
         $this->assertEventLegacyLogData($arr, $event);
     }
+
+    /**
+     * Test comment_created event.
+     */
+    public function test_blog_comment_created_event() {
+        global $USER, $CFG;
+
+        $this->setAdminUser();
+
+        require_once($CFG->dirroot . '/comment/lib.php');
+        $context = context_user::instance($USER->id);
+
+        $cmt = new stdClass();
+        $cmt->context = $context;
+        $cmt->courseid = $this->courseid;
+        $cmt->area = 'format_blog';
+        $cmt->itemid = $this->postid;
+        $cmt->showcount = 1;
+        $cmt->component = 'blog';
+        $manager = new comment($cmt);
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $manager->add("New comment");
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\core\event\blog_comment_created', $event);
+        $this->assertEquals($context, $event->get_context());
+        $this->assertEquals($this->postid, $event->other['itemid']);
+        $url = new moodle_url('/blog/index.php', array('entryid' => $this->postid));
+        $this->assertEquals($url, $event->get_url());
+    }
+
+    /**
+     * Test comment_deleted event.
+     */
+    public function test_blog_comment_deleted_event() {
+        global $USER, $CFG;
+
+        $this->setAdminUser();
+
+        require_once($CFG->dirroot . '/comment/lib.php');
+        $context = context_user::instance($USER->id);
+
+        $cmt = new stdClass();
+        $cmt->context = $context;
+        $cmt->courseid = $this->courseid;
+        $cmt->area = 'format_blog';
+        $cmt->itemid = $this->postid;
+        $cmt->showcount = 1;
+        $cmt->component = 'blog';
+        $manager = new comment($cmt);
+        $newcomment = $manager->add("New comment");
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $manager->delete($newcomment->id);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\core\event\blog_comment_deleted', $event);
+        $this->assertEquals($context, $event->get_context());
+        $this->assertEquals($this->postid, $event->other['itemid']);
+        $url = new moodle_url('/blog/index.php', array('entryid' => $this->postid));
+        $this->assertEquals($url, $event->get_url());
+    }
 }
 
index 55ee3ad..14eecd8 100644 (file)
@@ -129,14 +129,6 @@ class cachestore_dummy extends cache_store {
         return (!empty($this->definition));
     }
 
-    /**
-     * Returns true if this is ready.
-     * @return bool
-     */
-    public function is_ready() {
-        return true;
-    }
-
     /**
      * Returns true the given mode is supported.
      * @param int $mode
index f850e69..2a9621c 100644 (file)
@@ -236,6 +236,11 @@ class cache_factory {
     public function create_cache(cache_definition $definition) {
         $class = $definition->get_cache_class();
         $stores = cache_helper::get_stores_suitable_for_definition($definition);
+        foreach ($stores as $key => $store) {
+            if (!$store::are_requirements_met()) {
+                unset($stores[$key]);
+            }
+        }
         if (count($stores) === 0) {
             // Hmm still no stores, better provide a dummy store to mimic functionality. The dev will be none the wiser.
             $stores[] = $this->create_dummy_store($definition);
@@ -253,7 +258,7 @@ class cache_factory {
     /**
      * Creates a store instance given its name and configuration.
      *
-     * If the store has already been instantiated then the original objetc will be returned. (reused)
+     * If the store has already been instantiated then the original object will be returned. (reused)
      *
      * @param string $name The name of the store (must be unique remember)
      * @param array $details
@@ -267,6 +272,7 @@ class cache_factory {
             $store = new $class($details['name'], $details['configuration']);
             $this->stores[$name] = $store;
         }
+        /* @var cache_store $store */
         $store = $this->stores[$name];
         if (!$store->is_ready() || !$store->is_supported_mode($definition->get_mode())) {
             return false;
index 90076aa..c21ac47 100644 (file)
@@ -468,6 +468,7 @@ class cache_helper {
         $class = $store['class'];
 
         // Found the store: is it ready?
+        /* @var cache_store $instance */
         $instance = new $class($store['name'], $store['configuration']);
         if (!$instance->is_ready()) {
             unset($instance);
index d757157..aad5043 100644 (file)
@@ -179,7 +179,9 @@ abstract class cache_store implements cache_store_interface {
      * Returns true if this cache store instance is ready to use.
      * @return bool
      */
-    abstract public function is_ready();
+    public function is_ready() {
+        return forward_static_call(array($this, 'are_requirements_met'));
+    }
 
     /**
      * Retrieves an item from the cache store given its key.
index d5e245e..d320b8c 100644 (file)
@@ -222,14 +222,6 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
         return (is_array($this->store));
     }
 
-    /**
-     * Returns true if this store instance is ready to be used.
-     * @return bool
-     */
-    public function is_ready() {
-        return true;
-    }
-
     /**
      * Retrieves an item from the cache store given its key.
      *
index e54ee83..5f7de85 100644 (file)
@@ -217,14 +217,6 @@ class cachestore_static extends static_data_store implements cache_is_key_aware,
         return (is_array($this->store));
     }
 
-    /**
-     * Returns true if this store instance is ready to be used.
-     * @return bool
-     */
-    public function is_ready() {
-        return true;
-    }
-
     /**
      * Retrieves an item from the cache store given its key.
      *
index 38f9c4b..75ce1e6 100644 (file)
@@ -1,6 +1,9 @@
 This files describes API changes in /cache/stores/* - cache store plugins.
 Information provided here is intended especially for developers.
 
+=== 2.7 ===
+* cache_store::is_ready is no longer abstract, calling cache_store::are_requirements_met by default.
+
 === 2.6 ===
 * All cache instances are recorded and subsequent requests are given a reference to the original instance.
 * The persistent option for the cache definition has been deprecated. Please use the staticacceleration option instead.
index 8033ac0..443382f 100644 (file)
@@ -652,7 +652,11 @@ class comment {
             $newcmt->time = userdate($newcmt->timecreated, $newcmt->strftimeformat);
 
             // Trigger comment created event.
-            $eventclassname = '\\' . $this->component . '\\event\comment_created';
+            if (core_component::is_core_subsystem($this->component)) {
+                $eventclassname = '\\core\\event\\' . $this->component . '_comment_created';
+            } else {
+                $eventclassname = '\\' . $this->component . '\\event\comment_created';
+            }
             if (class_exists($eventclassname)) {
                 $event = $eventclassname::create(
                         array(
@@ -724,7 +728,11 @@ class comment {
         }
         $DB->delete_records('comments', array('id'=>$commentid));
         // Trigger comment delete event.
-        $eventclassname = '\\' . $this->component . '\\event\comment_deleted';
+        if (core_component::is_core_subsystem($this->component)) {
+            $eventclassname = '\\core\\event\\' . $this->component . '_comment_deleted';
+        } else {
+            $eventclassname = '\\' . $this->component . '\\event\comment_deleted';
+        }
         if (class_exists($eventclassname)) {
             $event = $eventclassname::create(
                     array(
index a26144d..9a02d19 100644 (file)
@@ -278,6 +278,14 @@ class helper {
             );
         }
 
+        if ($category->can_restore_courses_into()) {
+            $actions['restore'] = array(
+                'url' => new \moodle_url('/backup/restorefile.php', array('contextid' => $category->get_context()->id)),
+                'icon' => new \pix_icon('i/restore', new \lang_string('restorecourse', 'admin')),
+                'string' => new \lang_string('restorecourse', 'admin')
+            );
+        }
+
         return $actions;
     }
 
index d279d39..00b19d4 100644 (file)
@@ -736,38 +736,13 @@ M.course_dndupload = {
                     var result = JSON.parse(xhr.responseText);
                     if (result) {
                         if (result.error == 0) {
-                            // All OK - update the dummy element
-                            if (result.content) {
-                                // A label
-                                resel.indentdiv.innerHTML = '<div class="activityinstance" ></div>' + result.content + result.commands;
-                            } else {
-                                // Not a label
-                                resel.icon.src = result.icon;
-                                resel.a.href = result.link;
-                                resel.namespan.innerHTML = result.name;
-
-                                if (!parseInt(result.visible, 10)) {
-                                    resel.a.className = 'dimmed';
-                                }
-
-                                if (result.groupingname) {
-                                    resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
-                                } else {
-                                    resel.div.removeChild(resel.groupingspan);
-                                }
-
-                                resel.div.removeChild(resel.progressouter);
-                                resel.indentdiv.innerHTML += result.commands;
-                                if (result.onclick) {
-                                    resel.a.onclick = result.onclick;
-                                }
-                                if (self.Y.UA.gecko > 0) {
-                                    // Fix a Firefox bug which makes sites with a '~' in their wwwroot
-                                    // log the user out when clicking on the link (before refreshing the page).
-                                    resel.div.innerHTML = unescape(resel.div.innerHTML);
-                                }
+                            // All OK - replace the dummy element.
+                            resel.li.outerHTML = result.fullcontent;
+                            if (self.Y.UA.gecko > 0) {
+                                // Fix a Firefox bug which makes sites with a '~' in their wwwroot
+                                // log the user out when clicking on the link (before refreshing the page).
+                                resel.li.outerHTML = unescape(resel.li.outerHTML);
                             }
-                            resel.li.id = result.elementid;
                             self.add_editing(result.elementid);
                         } else {
                             // Error - remove the dummy element
@@ -986,39 +961,14 @@ M.course_dndupload = {
                     var result = JSON.parse(xhr.responseText);
                     if (result) {
                         if (result.error == 0) {
-                            // All OK - update the dummy element
-                            if (result.content) {
-                                // A label
-                                resel.indentdiv.innerHTML = '<div class="activityinstance" ></div>' + result.content + result.commands;
-                            } else {
-                                // Not a label
-                                resel.icon.src = result.icon;
-                                resel.a.href = result.link;
-                                resel.namespan.innerHTML = result.name;
-
-                                if (!parseInt(result.visible, 10)) {
-                                    resel.a.className = 'dimmed';
-                                }
-
-                                if (result.groupingname) {
-                                    resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
-                                } else {
-                                    resel.div.removeChild(resel.groupingspan);
-                                }
-
-                                resel.div.removeChild(resel.progressouter);
-                                resel.div.innerHTML += result.commands;
-                                if (result.onclick) {
-                                    resel.a.onclick = result.onclick;
-                                }
-                                if (self.Y.UA.gecko > 0) {
-                                    // Fix a Firefox bug which makes sites with a '~' in their wwwroot
-                                    // log the user out when clicking on the link (before refreshing the page).
-                                    resel.div.innerHTML = unescape(resel.div.innerHTML);
-                                }
+                            // All OK - replace the dummy element.
+                            resel.li.outerHTML = result.fullcontent;
+                            if (self.Y.UA.gecko > 0) {
+                                // Fix a Firefox bug which makes sites with a '~' in their wwwroot
+                                // log the user out when clicking on the link (before refreshing the page).
+                                resel.li.outerHTML = unescape(resel.li.outerHTML);
                             }
-                            resel.li.id = result.elementid;
-                            self.add_editing(result.elementid, sectionnumber);
+                            self.add_editing(result.elementid);
                         } else {
                             // Error - remove the dummy element
                             resel.parent.removeChild(resel.li);
index 3fa6bb2..84aea52 100644 (file)
@@ -722,29 +722,18 @@ class dndupload_ajax_processor {
      */
     protected function send_response($mod) {
         global $OUTPUT, $PAGE;
-        $courserenderer = $PAGE->get_renderer('core', 'course');
 
         $resp = new stdClass();
         $resp->error = self::ERROR_OK;
-        $resp->icon = $mod->get_icon_url()->out();
-        $resp->name = $mod->name;
-        if ($mod->has_view()) {
-            $resp->link = $mod->get_url()->out();
-        } else {
-            $resp->link = null;
-        }
-        $resp->content = $mod->get_content();
-        $resp->elementid = 'module-'.$mod->id;
-        $actions = course_get_cm_edit_actions($mod, 0, $mod->sectionnum);
-        $resp->commands = ' '. $courserenderer->course_section_cm_edit_actions($actions, $mod);
-        $resp->onclick = $mod->get_on_click();
-        $resp->visible = $mod->visible;
-
-        // If using groupings, then display grouping name.
-        if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', $this->context)) {
-            $groupings = groups_get_all_groupings($this->course->id);
-            $resp->groupingname = format_string($groupings[$mod->groupingid]->name);
-        }
+        $resp->elementid = 'module-' . $mod->id;
+
+        $courserenderer = $PAGE->get_renderer('core', 'course');
+        $completioninfo = new completion_info($this->course);
+        $info = get_fast_modinfo($this->course);
+        $sr = null;
+        $modulehtml = $courserenderer->course_section_cm($this->course, $completioninfo,
+                $mod, null, array());
+        $resp->fullcontent = $courserenderer->course_section_cm_list_item($this->course, $completioninfo, $mod, $sr);
 
         echo $OUTPUT->header();
         echo json_encode($resp);
index 2d61c28..f8b2fa4 100644 (file)
@@ -148,15 +148,15 @@ class core_course_external extends external_api {
                         $modcontext = context_module::instance($cm->id);
 
                         if (!empty($cm->showdescription) or $cm->modname == 'label') {
-                            // We want to use the external format. However from reading get_formatted_content(), get_content() format is always FORMAT_HTML.
-                            list($module['description'], $descriptionformat) = external_format_text($cm->get_content(),
+                            // We want to use the external format. However from reading get_formatted_content(), $cm->content format is always FORMAT_HTML.
+                            list($module['description'], $descriptionformat) = external_format_text($cm->content,
                                 FORMAT_HTML, $modcontext->id, $cm->modname, 'intro', $cm->id);
                         }
 
                         //url of the module
-                        $url = $cm->get_url();
+                        $url = $cm->url;
                         if ($url) { //labels don't have url
-                            $module['url'] = $cm->get_url()->out(false);
+                            $module['url'] = $url->out(false);
                         }
 
                         $canviewhidden = has_capability('moodle/course:viewhiddenactivities',
index 396e4d6..dfe2970 100644 (file)
@@ -100,7 +100,7 @@ class format_singleactivity extends format_base {
         if (!$cm->uservisible) {
             return null;
         }
-        $action = $cm->get_url();
+        $action = $cm->url;
         if (!$action) {
             // Do not add to navigation activity without url (i.e. labels).
             return null;
@@ -412,13 +412,13 @@ class format_singleactivity extends format_base {
                     // Student views an empty course page.
                     return;
                 }
-            } else if (!$cm->uservisible || !$cm->get_url()) {
+            } else if (!$cm->uservisible || !$cm->url) {
                 // Activity is set but not visible to current user or does not have url.
                 // Display course page (either empty or with availability restriction info).
                 return;
             } else {
                 // Everything is set up and accessible, redirect to the activity page!
-                redirect($cm->get_url());
+                redirect($cm->url);
             }
         }
     }
index bfc3495..9feeec5 100644 (file)
@@ -58,6 +58,23 @@ if (has_capability('moodle/user:loginas', $systemcontext)) {
         print_error('usernotincourse');
     }
     $context = $coursecontext;
+
+    // Check if course has SEPARATEGROUPS and user is part of that group.
+    if (groups_get_course_groupmode($course) == SEPARATEGROUPS &&
+            !has_capability('moodle/site:accessallgroups', $context)) {
+        $samegroup = false;
+        if ($groups = groups_get_all_groups($course->id, $USER->id)) {
+            foreach ($groups as $group) {
+                if (groups_is_member($group->id, $userid)) {
+                    $samegroup = true;
+                    break;
+                }
+            }
+        }
+        if (!$samegroup) {
+            print_error('nologinas');
+        }
+    }
 }
 
 // Login as this user and return to course home page.
index 1001212..e7f1b6b 100644 (file)
@@ -743,7 +743,7 @@ class core_course_renderer extends plugin_renderer_base {
             // nothing to be displayed to the user
             return $output;
         }
-        $url = $mod->get_url();
+        $url = $mod->url;
         if (!$url) {
             return $output;
         }
@@ -793,7 +793,7 @@ class core_course_renderer extends plugin_renderer_base {
 
         // Get on-click attribute value if specified and decode the onclick - it
         // has already been encoded for display (puke).
-        $onclick = htmlspecialchars_decode($mod->get_on_click(), ENT_QUOTES);
+        $onclick = htmlspecialchars_decode($mod->onclick, ENT_QUOTES);
 
         $groupinglabel = '';
         if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', context_course::instance($mod->course))) {
@@ -851,7 +851,7 @@ class core_course_renderer extends plugin_renderer_base {
         } else {
             $textclasses .= ' dimmed_text';
         }
-        if ($mod->get_url()) {
+        if ($mod->url) {
             if ($content) {
                 // If specified, display extra content after link.
                 $output = html_writer::tag('div', $content, array('class' =>
@@ -923,7 +923,7 @@ class core_course_renderer extends plugin_renderer_base {
     public function course_section_cm_list_item($course, &$completioninfo, cm_info $mod, $sectionreturn, $displayoptions = array()) {
         $output = '';
         if ($modulehtml = $this->course_section_cm($course, $completioninfo, $mod, $sectionreturn, $displayoptions)) {
-            $modclasses = 'activity ' . $mod->modname . ' modtype_' . $mod->modname . ' ' . $mod->get_extra_classes();
+            $modclasses = 'activity ' . $mod->modname . ' modtype_' . $mod->modname . ' ' . $mod->extraclasses;
             $output .= html_writer::tag('li', $modulehtml, array('class' => $modclasses, 'id' => 'module-' . $mod->id));
         }
         return $output;
@@ -937,7 +937,6 @@ class core_course_renderer extends plugin_renderer_base {
      *
      * This function calls:
      * {@link core_course_renderer::course_section_cm_name()}
-     * {@link cm_info::get_after_link()}
      * {@link core_course_renderer::course_section_cm_text()}
      * {@link core_course_renderer::course_section_cm_availability()}
      * {@link core_course_renderer::course_section_cm_completion()}
@@ -1005,7 +1004,7 @@ class core_course_renderer extends plugin_renderer_base {
             }
 
             // Module can put text after the link (e.g. forum unread)
-            $output .= $mod->get_after_link();
+            $output .= $mod->afterlink;
 
             // Closing the tag which contains everything but edit icons. Content part of the module should not be part of this.
             $output .= html_writer::end_tag('div'); // .activityinstance
@@ -1018,7 +1017,7 @@ class core_course_renderer extends plugin_renderer_base {
         // it should work similarly (at least in terms of ordering) to an
         // activity.
         $contentpart = $this->course_section_cm_text($mod, $displayoptions);
-        $url = $mod->get_url();
+        $url = $mod->url;
         if (empty($url)) {
             $output .= $contentpart;
         }
@@ -1027,7 +1026,7 @@ class core_course_renderer extends plugin_renderer_base {
         if ($this->page->user_is_editing()) {
             $editactions = course_get_cm_edit_actions($mod, $mod->indent, $sectionreturn);
             $modicons .= ' '. $this->course_section_cm_edit_actions($editactions, $mod, $displayoptions);
-            $modicons .= $mod->get_after_edit_icons();
+            $modicons .= $mod->afterediticons;
         }
 
         $modicons .= $this->course_section_cm_completion($course, $completioninfo, $mod, $displayoptions);
index 92a5f6c..994161a 100644 (file)
@@ -600,13 +600,13 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
         foreach($firstsection['modules'] as $module) {
             if ($module['id'] == $forumcm->id and $module['modname'] == 'forum') {
                 $cm = $modinfo->cms[$forumcm->id];
-                $formattedtext = format_text($cm->get_content(), FORMAT_HTML,
+                $formattedtext = format_text($cm->content, FORMAT_HTML,
                     array('noclean' => true, 'para' => false, 'filter' => false));
                 $this->assertEquals($formattedtext, $module['description']);
                 $testexecuted = $testexecuted + 1;
             } else if ($module['id'] == $labelcm->id and $module['modname'] == 'label') {
                 $cm = $modinfo->cms[$labelcm->id];
-                $formattedtext = format_text($cm->get_content(), FORMAT_HTML,
+                $formattedtext = format_text($cm->content, FORMAT_HTML,
                     array('noclean' => true, 'para' => false, 'filter' => false));
                 $this->assertEquals($formattedtext, $module['description']);
                 $testexecuted = $testexecuted + 1;
index 1746697..6ad641f 100644 (file)
@@ -1058,7 +1058,7 @@ class course_enrolment_manager {
                     continue;
                 } else if ($ue->timestart and $ue->timeend) {
                     $period = get_string('periodstartend', 'enrol', array('start'=>userdate($ue->timestart), 'end'=>userdate($ue->timeend)));
-                    $periodoutside = ($ue->timestart && $ue->timeend && $now < $ue->timestart && $now > $ue->timeend);
+                    $periodoutside = ($ue->timestart && $ue->timeend && ($now < $ue->timestart || $now > $ue->timeend));
                 } else if ($ue->timestart) {
                     $period = get_string('periodstart', 'enrol', userdate($ue->timestart));
                     $periodoutside = ($ue->timestart && $now < $ue->timestart);
index f68ba22..f4a357c 100644 (file)
@@ -473,9 +473,12 @@ class grade_report_grader extends grade_report {
                            AND ue.status = :uestatus
                            AND e.status = :estatus
                            AND e.courseid = :courseid
+                           AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)
                   GROUP BY ue.userid";
             $coursecontext = $this->context->get_course_context(true);
-            $params = array_merge($uparams, array('estatus'=>ENROL_INSTANCE_ENABLED, 'uestatus'=>ENROL_USER_ACTIVE, 'courseid'=>$coursecontext->instanceid));
+            $time = time();
+            $params = array_merge($uparams, array('estatus' => ENROL_INSTANCE_ENABLED, 'uestatus' => ENROL_USER_ACTIVE,
+                    'courseid' => $coursecontext->instanceid, 'now1' => $time, 'now2' => $time));
             $useractiveenrolments = $DB->get_records_sql($sql, $params);
 
             $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
index 07c59e7..f3d768c 100644 (file)
@@ -99,9 +99,14 @@ class core_grade_edittreelib_testcase extends advanced_testcase {
         $this->assertEquals($scale->id, $gradeitem->scaleid);
         $this->assertEquals($scalestring, $cell->text, "Grade text matches scale");
 
-        // Now change it to no grade.
+        // Now change it to no grade with gradebook feedback enabled.
+        $adminconfig = $assign->get_admin_config();
+        $gradebookplugin = $adminconfig->feedback_plugin_for_gradebook;
+        $gradebookplugin .= '_enabled';
+
         $instance = $assign->get_instance();
         $instance->grade = 0;
+        $instance->$gradebookplugin = 1;
         $instance->instance = $instance->id;
         $assign->update_instance($instance);
 
@@ -111,6 +116,19 @@ class core_grade_edittreelib_testcase extends advanced_testcase {
         $this->assertEquals(GRADE_TYPE_TEXT, $gradeitem->gradetype);
         $this->assertEquals(null, $gradeitem->scaleid);
         $this->assertEquals(' - ', $cell->text, 'Grade text matches empty value of " - "');
+
+        // Now change it to no grade with gradebook feedback disabled.
+        $instance = $assign->get_instance();
+        $instance->grade = 0;
+        $instance->$gradebookplugin = 0;
+        $instance->instance = $instance->id;
+        $assign->update_instance($instance);
+
+        $gradeitem = grade_item::fetch($gradeitemparams);
+        $cell = $column->get_item_cell($gradeitem, array());
+
+        $this->assertEquals(GRADE_TYPE_NONE, $gradeitem->gradetype);
+        $this->assertEquals(null, $gradeitem->scaleid);
     }
 }
 
index c7f4fc5..75c7ccf 100644 (file)
@@ -108,10 +108,6 @@ $config = new stdClass();
 $config->lang = $lang;
 
 if (!empty($_POST)) {
-    if (install_ini_get_bool('magic_quotes_gpc')) {
-        $_POST = array_map('stripslashes', $_POST);
-    }
-
     $config->stage = (int)$_POST['stage'];
 
     if (isset($_POST['previous'])) {
index 7006d1a..5bff7f6 100644 (file)
@@ -490,7 +490,6 @@ $string['enablesafebrowserintegration'] = 'Enable Safe Exam Browser integration'
 $string['enablestats'] = 'Enable statistics';
 $string['enabletgzbackups'] = 'Enable new backup format';
 $string['enabletgzbackups_desc'] = 'If enabled, future backups will be created in a new compression format for .mbz files (internally stored as a .tar.gz file). This removes the 4GB backup size restriction and may improve performance. Restore supports both formats and the difference should be transparent to users.';
-$string['enabletgzbackups_nozlib'] = 'PHP extension &lsquo;zlib&rsquo; is not available. The new backup format relies on this extension and will be disabled until zlib is installed and enabled.';
 $string['enabletrusttext'] = 'Enable trusted content';
 $string['enablewebservices'] = 'Enable web services';
 $string['enablewsdocumentation'] = 'Web services documentation';
@@ -521,7 +520,6 @@ $string['experimental'] = 'Experimental';
 $string['experimentalsettings'] = 'Experimental settings';
 $string['extendedusernamechars'] = 'Allow extended characters in usernames';
 $string['extramemorylimit'] = 'Extra PHP memory limit';
-$string['fatalmagicquotesruntime'] = '<p>Serious configuration error detected, please notify server administrator.</p><p> To operate properly, Moodle requires that administrator changes PHP settings.</p><p><code>magic_quotes_runtime</code> must be set to <code>off</code>.</p><p>This setting is controlled by editing <code>php.ini</code>, Apache/IIS <br />configuration or <code>.htaccess</code> file on the server.</p>';
 $string['fatalsessionautostart'] = '<p>Serious configuration error detected, please notify server administrator.</p><p> To operate properly, Moodle requires that administrator changes PHP settings.</p><p><code>session.auto_start</code> must be set to <code>off</code>.</p><p>This setting is controlled by editing <code>php.ini</code>, Apache/IIS <br />configuration or <code>.htaccess</code> file on the server.</p>';
 $string['filecreated'] = 'New file created';
 $string['filestoredin'] = 'Save file into folder :';
@@ -921,6 +919,7 @@ $string['purgecaches']= 'Purge all caches';
 $string['purgecachesconfirm']= 'Moodle can cache themes, javascript, language strings, filtered text, rss feeds and many other pieces of calculated data.  Purging these caches will delete that data from the server and force browsers to refetch data, so that you can be sure you are seeing the most up-to-date values produced by the current code.  There is no danger in purging caches, but your site may appear slower for a while until the server and clients calculate new information and cache it.';
 $string['purgecachesfinished']= 'All caches were purged.';
 $string['requestcategoryselection'] = 'Enable category selection';
+$string['restorecourse'] = 'Restore course';
 $string['restorernewroleid'] = 'Restorers\' role in courses';
 $string['restorernewroleid_help'] = 'If the user does not already have the permission to manage the newly restored course, the user is automatically assigned this role and enrolled if necessary. Select "None" if you do not want restorers to be able to manage every restored course.';
 $string['reverseproxy'] = 'Reverse proxy';
@@ -1127,7 +1126,6 @@ $string['webproxyinfo'] = 'Fill in following options if your Moodle server can n
 $string['xmlrpcrecommended'] = 'The xmlrpc extension is needed for hub communication, and useful for web services and Moodle networking';
 $string['yuicomboloading'] = 'YUI combo loading';
 $string['ziprequired'] = 'The Zip PHP extension is now required by Moodle, info-ZIP binaries or PclZip library are not used anymore.';
-$string['zlibenabled'] = 'zlib enabled';
 
 
 $string['caching'] = 'Caching';
index c7d814f..e37caaa 100644 (file)
@@ -117,7 +117,6 @@ $string['errorminbackup20version'] = 'This backup file has been created with one
 $string['errorrestorefrontpage'] = 'Restoring over front page is not allowed.';
 $string['errorinvalidformat'] = 'Unknown backup format';
 $string['errorinvalidformatinfo'] = 'The selected file is not a valid Moodle backup file and can\'t be restored.';
-$string['errortgznozlib'] = 'The selected file is in the new backup format and cannot be restored because the zlib PHP extension is not available on this system.';
 $string['executionsuccess'] = 'The backup file was successfully created.';
 $string['filename'] = 'Filename';
 $string['filealiasesrestorefailures'] = 'Aliases restore failures';
index 14cd22b..099d8e7 100644 (file)
@@ -55,6 +55,10 @@ $string['anymethodactivity'] = 'Any of the selected activities is complete';
 $string['anymethodcourseset'] = 'Any of the selected courses is complete';
 $string['anymethodmanual'] = 'Any of the selected roles awards the badge';
 $string['anymethodprofile'] = 'Any of the selected profile fields has been completed';
+$string['archivebadge'] = 'Would you like to delete badge \'{$a}\', but keep existing issued badges?';
+$string['archiveconfirm'] = 'Delete and keep existing issued badges';
+$string['archivehelp'] = '<p>This option means that the badge will be marked as "retired" and will no longer appear in the list of badges. Users will no longer be able to earn this badge, however existing badge recipients will still be able to display this badge on their profile page and push it to their external backpacks.</p>
+<p>If you would like your users to retain access to the earned badges it is important to select this option instead of fully deleting badges.</p>';
 $string['attachment'] = 'Attach badge to message';
 $string['attachment_help'] = 'If checked, an issued badge file will be attached to the recepient\'s email for download. Email attachments must be enabled in site settings to use this option.';
 $string['award'] = 'Award badge';
@@ -196,8 +200,10 @@ $string['defaultissuercontact'] = 'Default badge issuer contact details';
 $string['defaultissuercontact_desc'] = 'An email address associated with the badge issuer.';
 $string['defaultissuername'] = 'Default badge issuer name';
 $string['defaultissuername_desc'] = 'Name of the issuing agent or authority.';
-$string['delbadge'] = 'Delete badge';
-$string['delconfirm'] = 'Are you sure that you want to delete badge \'{$a}\'?';
+$string['delbadge'] = 'Would you like to delete badge \'{$a}\' and remove all existing issued badges?';
+$string['delconfirm'] = 'Delete and remove existing issued badges';
+$string['deletehelp'] = '<p>Fully deleting a badge means that all its information and criteria records will be permanently removed. Users who have earned this badge will no longer be able to access it and display it on their profile pages.</p>
+<p>Note: Users who have earned this badge and have already pushed it to their external backpack, will still have this badge in their external backpack. However, they will not be able to access criteria and evidence pages linking back to this web site.</p>';
 $string['delcritconfirm'] = 'Are you sure that you want to delete this criterion?';
 $string['delparamconfirm'] = 'Are you sure that you want to delete this parameter?';
 $string['description'] = 'Description';
index 882655a..e9da636 100644 (file)
@@ -145,15 +145,6 @@ $string['inputwebdirectory'] = 'Moodle directory:';
 $string['installation'] = 'Installation';
 $string['langdownloaderror'] = 'Unfortunately the language "{$a}" could not be downloaded. The installation process will continue in English.';
 $string['langdownloadok'] = 'The language "{$a}" was installed successfully. The installation process will continue in this language.';
-$string['magicquotesruntime'] = 'Magic quotes run time';
-$string['magicquotesruntimeerror'] = 'This should be off';
-$string['magicquotesruntimehelp'] = '<p>Magic quotes runtime should be turned off for Moodle to function properly.</p>
-
-<p>Normally it is off by default ... see the setting <b>magic_quotes_runtime</b> in your php.ini file.</p>
-
-<p>If you don\'t have access to your php.ini, you might be able to place the following line in a file 
-   called .htaccess within your Moodle directory:</p>
-   <blockquote><div>php_value magic_quotes_runtime Off</div></blockquote>';
 $string['memorylimit'] = 'Memory limit';
 $string['memorylimiterror'] = 'The PHP memory limit is set quite low ... you may run into problems later.';
 $string['memorylimithelp'] = '<p>The PHP memory limit for your server is currently set to {$a}.</p>
index a190faa..41c86ef 100644 (file)
@@ -1660,11 +1660,21 @@ abstract class admin_setting {
             rebuild_course_cache(0, true);
         }
 
-        add_to_config_log($name, $oldvalue, $value, $this->plugin);
+        $this->add_to_config_log($name, $oldvalue, $value);
 
         return true; // BC only
     }
 
+    /**
+     * Log config changes if necessary.
+     * @param string $name
+     * @param string $oldvalue
+     * @param string $value
+     */
+    protected function add_to_config_log($name, $oldvalue, $value) {
+        add_to_config_log($name, $oldvalue, $value, $this->plugin);
+    }
+
     /**
      * Returns current value of this setting
      * @return mixed array or string depending on instance, NULL means not set yet
@@ -2161,6 +2171,22 @@ class admin_setting_configpasswordunmask extends admin_setting_configtext {
         parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
     }
 
+    /**
+     * Log config changes if necessary.
+     * @param string $name
+     * @param string $oldvalue
+     * @param string $value
+     */
+    protected function add_to_config_log($name, $oldvalue, $value) {
+        if ($value !== '') {
+            $value = '********';
+        }
+        if ($oldvalue !== '' and $oldvalue !== null) {
+            $oldvalue = '********';
+        }
+        parent::add_to_config_log($name, $oldvalue, $value);
+    }
+
     /**
      * Returns XHTML for the field
      * Writes Javascript into the HTML below right before the last div
index 8d1bf9e..f233078 100644 (file)
@@ -603,13 +603,42 @@ class badge {
     }
 
     /**
-     * Marks the badge as archived.
-     * For reporting and historical purposed we cannot completely delete badges.
-     * We will just change their status to BADGE_STATUS_ARCHIVED.
+     * Fully deletes the badge or marks it as archived.
+     *
+     * @param $archive bool Achive a badge without actual deleting of any data.
      */
-    public function delete() {
-        $this->status = BADGE_STATUS_ARCHIVED;
-        $this->save();
+    public function delete($archive = true) {
+        global $DB;
+
+        if ($archive) {
+            $this->status = BADGE_STATUS_ARCHIVED;
+            $this->save();
+            return;
+        }
+
+        $fs = get_file_storage();
+
+        // Remove all issued badge image files and badge awards.
+        // Cannot bulk remove area files here because they are issued in user context.
+        $awards = $this->get_awards();
+        foreach ($awards as $award) {
+            $usercontext = context_user::instance($award->userid);
+            $fs->delete_area_files($usercontext->id, 'badges', 'userbadge', $this->id);
+        }
+        $DB->delete_records('badge_issued', array('badgeid' => $this->id));
+
+        // Remove all badge criteria.
+        $criteria = $this->get_criteria();
+        foreach ($criteria as $criterion) {
+            $criterion->delete();
+        }
+
+        // Delete badge images.
+        $badgecontext = $this->get_context();
+        $fs->delete_area_files($badgecontext->id, 'badges', 'badgeimage', $this->id);
+
+        // Finally, remove badge itself.
+        $DB->delete_records('badge', array('id' => $this->id));
     }
 }
 
index 73f9b61..fb220d1 100644 (file)
@@ -47,6 +47,11 @@ class behat_form_checkbox extends behat_form_field {
      */
     public function set_value($value) {
 
+        if (!$this->running_javascript()) {
+            $this->field->check();
+            return;
+        }
+
         if (!empty($value) && !$this->field->isChecked()) {
             // Check it if it should be checked and it is not.
             $this->field->click();
index e6ea562..ce70ef0 100644 (file)
@@ -1013,4 +1013,14 @@ $cache = '.var_export($cache, true).';
             opcache_invalidate($file, true);
         }
     }
+
+    /**
+     * Return true if subsystemname is core subsystem.
+     *
+     * @param string $subsystemname name of the subsystem.
+     * @return bool true if core subsystem.
+     */
+    public static function is_core_subsystem($subsystemname) {
+        return isset(self::$subsystems[$subsystemname]);
+    }
 }
index 4e4ed8d..46aa825 100644 (file)
@@ -36,6 +36,13 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Both events could be triggered in a row, first the uploaded, then the submitted.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type array pathnamehashes uploaded files path name hashes.
+ *      @type string content string.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 5670f52..0e7da1c 100644 (file)
@@ -29,6 +29,15 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a new blog entry is associated with a context.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string associatetype type of blog association, course/coursemodule.
+ *      @type int blogid id of blog.
+ *      @type int associateid id of associate.
+ *      @type string subject blog subject.
+ * }
+ *
  * @package    core
  * @copyright  2013 onwards Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
diff --git a/lib/classes/event/blog_comment_created.php b/lib/classes/event/blog_comment_created.php
new file mode 100644 (file)
index 0000000..1ac2850
--- /dev/null
@@ -0,0 +1,53 @@
+<?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/>.
+
+/**
+ * blog comment created event.
+ *
+ * @package    core
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * blog comment created event.
+ *
+ * @package    core
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class blog_comment_created extends \core\event\comment_created {
+    /**
+     * Get URL related to the action.
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return new \moodle_url('/blog/index.php', array('entryid' => $this->other['itemid']));
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return 'User with id ' . $this->userid . ' added comment for blog with id ' . $this->other['itemid'];
+    }
+}
diff --git a/lib/classes/event/blog_comment_deleted.php b/lib/classes/event/blog_comment_deleted.php
new file mode 100644 (file)
index 0000000..cf8e7da
--- /dev/null
@@ -0,0 +1,53 @@
+<?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/>.
+
+/**
+ * blog comment deleted event.
+ *
+ * @package    core
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * blog comment deleted event.
+ *
+ * @package    core
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class blog_comment_deleted extends \core\event\comment_deleted {
+    /**
+     * Get URL related to the action.
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return new \moodle_url('/blog/index.php', array('entryid' => $this->other['itemid']));
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return 'User with id ' . $this->userid . ' deleted comment for blog with id ' . $this->other['itemid'];
+    }
+}
index bf4dbaf..d0119fa 100644 (file)
@@ -29,6 +29,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when blog entries are viewed.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int courseid id of associated course.
+ * }
+ *
  * @package    core
  * @copyright  2013 onwards Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index abee52e..ffd8874 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * This class has to be extended by any event which is triggred while creating new comment.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int itemid id of item for which comment is added.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -63,10 +69,19 @@ abstract class comment_created extends \core\event\base {
      * @return string
      */
     public function get_description() {
-        return 'User with id '. $this->userid . ' added comment for ' . $this->component . ' with instance id ' .
+        return 'User with id ' . $this->userid . ' added comment for ' . $this->component . ' with instance id ' .
                 $this->contextinstanceid;
     }
 
+    /**
+     * Get URL related to the action.
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return $this->context->get_url();
+    }
+
     /**
      * Custom validation.
      *
index f6a2004..fca1472 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * This class has to be extended by any event which is triggred while deleting comment.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int itemid id of item for which comment is deleted.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -63,10 +69,19 @@ abstract class comment_deleted extends \core\event\base {
      * @return string
      */
     public function get_description() {
-        return 'User with id '. $this->userid . ' deleted comment for ' . $this->component . ' with instance id ' .
+        return 'User with id ' . $this->userid . ' deleted comment for ' . $this->component . ' with instance id ' .
                 $this->contextinstanceid;
     }
 
+    /**
+     * Get URL related to the action.
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return $this->context->get_url();
+    }
+
     /**
      * Custom validation.
      *
index 1f6aade..05618f0 100644 (file)
@@ -65,4 +65,13 @@ abstract class comments_viewed extends \core\event\base {
         return 'User with id '. $this->userid . ' viewed comments for ' . $this->component . ' with instance id ' .
                 $this->objectid;
     }
+
+    /**
+     * Get URL related to the action.
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return $this->context->get_url();
+    }
 }
index 7492bd1..17f0328 100644 (file)
@@ -39,6 +39,12 @@ defined('MOODLE_INTERNAL') || die();
  *  $event->trigger();
  * where \report_participation\event\content_viewed extends \core\event\content_viewed
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string content viewed content identifier.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index ff7ecf3..a856ef1 100644 (file)
@@ -19,7 +19,13 @@ namespace core\event;
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * category deleted event.
+ * Category deleted event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string name category name.
+ * }
  *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
index 92fc9a6..d5b6624 100644 (file)
@@ -21,6 +21,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course content_deleted event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type array options list of options which were skipped while deleting course content.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index deeacb4..57eb640 100644 (file)
@@ -21,6 +21,13 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course created event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string shortname shortname of course.
+ *      @type string fullname fullname of course.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 0f704a7..0580e7c 100644 (file)
@@ -21,6 +21,14 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course deleted event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string shortname shortname of course.
+ *      @type string fullname fullname of course.
+ *      @type string idnumber id number of course.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 9ed6fc8..2c481a8 100644 (file)
 /**
  * Event to be triggered when a new course module is created.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string modulename name of module created.
+ *      @type string name title of module.
+ *      @type string instanceid id of module instance.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
index 67a4b02..d00a43a 100644 (file)
@@ -30,6 +30,13 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a course module is deleted.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string modulename name of module deleted.
+ *      @type string instanceid id of module instance.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
index ced4210..99e61f8 100644 (file)
@@ -30,6 +30,14 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a course module is updated.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string modulename name of module updated.
+ *      @type string name title of module.
+ *      @type string instanceid id of module instance.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
index 56e1009..5c8f280 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core course reset ended event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type array reset_options all reset options settings including courseid.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 8a34a75..f28d6de 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core course reset started event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type array reset_options all reset options settings including courseid.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 2f8fa4f..8e7af36 100644 (file)
@@ -21,6 +21,16 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course restored event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string type restore type, activity, course or section.
+ *      @type int target where restored (new/existing/current/adding/deleting)
+ *      @type int mode execution mode
+ *      @type string opertaion restore
+ *      @type boolean samesite true is restored to same site.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 5a7d9e0..60760e5 100644 (file)
@@ -29,6 +29,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course section updated.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int sectionnum section number.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index c037d20..47ab3af 100644 (file)
@@ -21,6 +21,13 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course updated event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string shortname shortname of course.
+ *      @type string fullname fullname of course.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index df1c2d1..6855e15 100644 (file)
@@ -28,6 +28,13 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core_group member added event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string component name of component
+ *      @type int itemid id of item.
+ * }
+ *
  * @package    core_group
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 838ba8c..e3ce2ab 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a note is created.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string publishstate publish state.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 45249fe..52f9182 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a note is deleted.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string publishstate publish state
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index df3ac78..fb94617 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a note is updated.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string publishstate publish state.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 3680fc4..a298106 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a note is viewed.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string content hard-coded to notes.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 5213900..f22fd16 100644 (file)
@@ -21,6 +21,14 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Role assigned event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int id role assigned id.
+ *      @type string component name of component.
+ *      @type int itemid id of item.
+ * }
+ *
  * @package    core
  * @copyright  2013 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index d11dab8..ae150c8 100644 (file)
@@ -21,6 +21,14 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Role assigned event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string shortname shortname of role.
+ *      @type string description role description.
+ *      @type string archetype role type.
+ * }
+ *
  * @package    core_event
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 2e5a986..f3d0850 100644 (file)
@@ -21,6 +21,14 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Role unassigned event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int id role assigned id.
+ *      @type string component name of component.
+ *      @type int itemid id of item.
+ * }
+ *
  * @package    core
  * @copyright  2013 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index e04ee16..fdc68c8 100644 (file)
@@ -28,6 +28,16 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when user profile is deleted.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string username name of user.
+ *      @type string email user email.
+ *      @type string idnumber user idnumber.
+ *      @type string picture user picture.
+ *      @type int mnethostid mnet host id.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 064ccf5..c5e0d0e 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when user is enrolled in a course.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string enrol name of enrolment instance.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 8992347..4376a2b 100644 (file)
 /**
  * User enrolment deleted event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string enrol name of enrolment instance.
+ *      @type array userenrolment user_enrolment record.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 8e53236..69e71de 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when user enrolment is updated.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string enrol name of enrolment instance.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 45aa787..fce1f0d 100644 (file)
 /**
  * Defines the user list viewed event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int courseid id of course.
+ *      @type string courseshortname short name of course.
+ *      @type string coursefullname full name of course.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 9628e31..0bb4e17 100644 (file)
@@ -29,6 +29,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * User login event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string username name of user.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 50012d8..136307d 100644 (file)
@@ -29,6 +29,13 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * User loggedinas event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string originalusername original username.
+ *      @type string loggedinasusername username of logged in as user.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 8f2c6aa..d17f0bf 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when user logout.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string sessionid session id.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index af9f228..eefc9bf 100644 (file)
 /**
  * Defines the user profile viewed event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int courseid id of course.
+ *      @type string courseshortname short name of course.
+ *      @type string coursefullname fullname of course.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 9914385..1334784 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core webservice function_called event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string function name of the function.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 395e91b..9ababb0 100644 (file)
@@ -28,6 +28,14 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core web service login_failed event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string method authentication method.
+ *      @type string reason failure reason.
+ *      @type string tokenid id of token.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 436a236..22fd29c 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core webservice service created event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string sessionid session id.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 5f18336..d5799e0 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core webservice token_created event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type bool auto automatically created.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 8192704..36af200 100644 (file)
@@ -142,14 +142,14 @@ function min_enable_zlib_compression() {
 
     // zlib.output_compression is preferred over ob_gzhandler()
     if (!empty($_SERVER['HTTP_USER_AGENT']) and strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 6') !== false) {
-        @ini_set('zlib.output_compression', 'Off');
+        ini_set('zlib.output_compression', 'Off');
         if (function_exists('apache_setenv')) {
-            @apache_setenv('no-gzip', 1);
+            apache_setenv('no-gzip', 1);
         }
         return false;
     }
 
-    @ini_set('output_handler', '');
+    ini_set('output_handler', '');
 
     /*
      * docs clearly say 'on' means enable and number means size of buffer,
@@ -157,7 +157,7 @@ function min_enable_zlib_compression() {
      * 1 probably sets chunk size to 4096. our CSS and JS scripts are much bigger,
      * so let's try some bigger sizes.
      */
-    @ini_set('zlib.output_compression', 65536);
+    ini_set('zlib.output_compression', 65536);
 
     return true;
 }
index 9323ea5..078659a 100644 (file)
@@ -2395,6 +2395,14 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
         return $this->has_manage_capability();
     }
 
+    /**
+     * Returns true if the user is able to restore a course into this category as a new course.
+     * @return bool
+     */
+    public function can_restore_courses_into() {
+        return has_capability('moodle/course:create', $this->get_context());
+    }
+
     /**
      * Resorts the sub categories of this category by the given field.
      *
index 0a80bd0..b0f8134 100644 (file)
@@ -2862,5 +2862,44 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2013111800.01);
     }
 
+    if ($oldversion < 2013122400.01) {
+        // Purge stored passwords from config_log table, ideally this should be in each plugin
+        // but that would complicate backporting...
+        $items = array(
+            'core/cronremotepassword', 'core/proxypassword', 'core/smtppass', 'core/jabberpassword',
+            'enrol_database/dbpass', 'enrol_ldap/bind_pw', 'url/secretphrase');
+        foreach ($items as $item) {
+            list($plugin, $name) = explode('/', $item);
+            if ($plugin === 'core') {
+                $sql = "UPDATE {config_log}
+                           SET value = :value
+                         WHERE name = :name AND plugin IS NULL AND value <> ''";
+                $params = array('value'=>'********', 'name'=>$name);
+                $DB->execute($sql, $params);
+
+                $sql = "UPDATE {config_log}
+                           SET oldvalue = :value
+                         WHERE name = :name AND plugin IS NULL AND oldvalue <> ''";
+                $params = array('value'=>'********', 'name'=>$name);
+                $DB->execute($sql, $params);
+
+            } else {
+                $sql = "UPDATE {config_log}
+                           SET value = :value
+                         WHERE name = :name AND plugin = :plugin AND value <> ''";
+                $params = array('value'=>'********', 'name'=>$name, 'plugin'=>$plugin);
+                $DB->execute($sql, $params);
+
+                $sql = "UPDATE {config_log}
+                           SET oldvalue = :value
+                         WHERE name = :name AND plugin = :plugin AND oldvalue <> ''";
+                $params = array('value'=>'********', 'name'=>$name, 'plugin'=>$plugin);
+                $DB->execute($sql, $params);
+            }
+        }
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2013122400.01);
+    }
+
     return true;
 }
index 7de1edb..4d54a14 100644 (file)
@@ -40,6 +40,15 @@ class tinymce_managefiles extends editor_tinymce_plugin {
             array $options = null) {
         global $USER;
 
+        if (!isloggedin() or isguestuser()) {
+            // Must be a real user to manage any files.
+            return;
+        }
+        if (!isset($options['maxfiles']) or $options['maxfiles'] == 0) {
+            // No files allowed - easy, do not load anything.
+            return;
+        }
+
         // Add parameters for filemanager
         $params['managefiles'] = array('usercontext' => context_user::instance($USER->id)->id);
         foreach (array('itemid', 'context', 'areamaxbytes', 'maxbytes', 'subdirs', 'return_types') as $key) {
index 32cafba..b5767e7 100644 (file)
@@ -2672,7 +2672,7 @@ function fulldelete($location) {
  */
 function byteserving_send_file($handle, $mimetype, $ranges, $filesize) {
     // better turn off any kind of compression and buffering
-    @ini_set('zlib.output_compression', 'Off');
+    ini_set('zlib.output_compression', 'Off');
 
     $chunksize = 1*(1024*1024); // 1MB chunks - must be less than 2MB!
     if ($handle === false) {
@@ -2924,7 +2924,7 @@ class curl {
         }
 
         if (!isset($this->emulateredirects)) {
-            $this->emulateredirects = (ini_get('open_basedir') or ini_get('safe_mode'));
+            $this->emulateredirects = ini_get('open_basedir');
         }
     }
 
index c4c08e2..d9dfed9 100644 (file)
@@ -146,7 +146,7 @@ class mbz_packer extends file_packer {
         global $CFG;
         require_once($CFG->dirroot . '/lib/filestorage/tgz_packer.php');
 
-        if ($CFG->enabletgzbackups && tgz_packer::has_required_extension()) {
+        if ($CFG->enabletgzbackups) {
             return get_file_packer('application/x-gzip');
         } else {
             return get_file_packer('application/zip');
@@ -158,18 +158,13 @@ class mbz_packer extends file_packer {
      *
      * @param string|stored_file $archivefile full pathname of zip file or stored_file instance
      * @return file_packer Suitable packer
-     * @throws moodle_exception If the file cannot be restored because of missing zlib
      */
     protected function get_packer_for_read_operation($archivefile) {
         global $CFG;
         require_once($CFG->dirroot . '/lib/filestorage/tgz_packer.php');
 
         if (tgz_packer::is_tgz_file($archivefile)) {
-            if (tgz_packer::has_required_extension()) {
-                return get_file_packer('application/x-gzip');
-            } else {
-                throw new moodle_exception('errortgznozlib', 'backup');
-            }
+            return get_file_packer('application/x-gzip');
         } else {
             return get_file_packer('application/zip');
         }
index b232e4f..682ec47 100644 (file)
@@ -36,10 +36,6 @@ class core_files_mbz_packer_testcase extends advanced_testcase {
         // Get backup packer.
         $packer = get_file_packer('application/vnd.moodle.backup');
         require_once($CFG->dirroot . '/lib/filestorage/tgz_packer.php');
-        if (!tgz_packer::has_required_extension()) {
-            $this->markTestSkipped('zlib not available');
-            return;
-        }
 
         // Set up basic archive contents.
         $files = array('1.txt' => array('frog'));
index d495ec8..d61d264 100644 (file)
@@ -114,9 +114,6 @@ class core_files_tgz_packer_testcase extends advanced_testcase implements file_p
     public function test_to_normal_files() {
         global $CFG;
         $packer = get_file_packer('application/x-gzip');
-        if (self::skip_because_missing_zlib()) {
-            return;
-        }
 
         // Archive files.
         $files = $this->prepare_file_list();
@@ -157,9 +154,6 @@ class core_files_tgz_packer_testcase extends advanced_testcase implements file_p
      */
     public function test_to_stored_files() {
         global $CFG;
-        if (self::skip_because_missing_zlib()) {
-            return;
-        }
         $packer = get_file_packer('application/x-gzip');
 
         // Archive files.
@@ -226,9 +220,6 @@ class core_files_tgz_packer_testcase extends advanced_testcase implements file_p
      */
     public function test_only_specified_files() {
         global $CFG;
-        if (self::skip_because_missing_zlib()) {
-            return;
-        }
         $packer = get_file_packer('application/x-gzip');
 
         // Archive files.
@@ -261,9 +252,6 @@ class core_files_tgz_packer_testcase extends advanced_testcase implements file_p
      */
     public function test_file_progress() {
         global $CFG;
-        if (self::skip_because_missing_zlib()) {
-            return;
-        }
 
         // Set up.
         $filelist = $this->prepare_file_list();
@@ -321,9 +309,6 @@ class core_files_tgz_packer_testcase extends advanced_testcase implements file_p
      */
     public function test_list_files() {
         global $CFG;
-        if (self::skip_because_missing_zlib()) {
-            return;
-        }
 
         // Set up.
         $filelist = $this->prepare_file_list();
@@ -391,9 +376,6 @@ class core_files_tgz_packer_testcase extends advanced_testcase implements file_p
 
     public function test_is_tgz_file() {
         global $CFG;
-        if (self::skip_because_missing_zlib()) {
-            return;
-        }
 
         // Set up.
         $filelist = $this->prepare_file_list();
@@ -446,19 +428,4 @@ class core_files_tgz_packer_testcase extends advanced_testcase implements file_p
     public function progress($progress = file_progress::INDETERMINATE, $max = file_progress::INDETERMINATE) {
         $this->progress[] = array($progress, $max);
     }
-
-    /**
-     * Checks if zlib is available. If not, marks current test as skipped.
-     *
-     * @return bool True if text should be skipped
-     */
-    protected function skip_because_missing_zlib() {
-        global $CFG;
-        require_once($CFG->dirroot . '/lib/filestorage/tgz_packer.php');
-        if (!tgz_packer::has_required_extension()) {
-            $this->markTestSkipped('zlib not available');
-            return true;
-        }
-        return false;
-    }
 }
index c47662a..5aea584 100644 (file)
@@ -700,7 +700,9 @@ class tgz_packer extends file_packer {
      * The zlib extension is required for this packer to work. This is a single
      * location for the code to check whether the extension is available.
      *
-     * @return bool True if the extension is available OK
+     * @deprecated since 2.7 Always true because zlib extension is now required.
+     *
+     * @return bool True if the zlib extension is available OK
      */
     public static function has_required_extension() {
         return extension_loaded('zlib');
index d0597fc..eca6360 100644 (file)
@@ -27,8 +27,6 @@ DirectoryIndex index.php index.html index.htm
 
 ### Thirdly, set up some PHP variables that Moodle needs
 
-php_flag magic_quotes_gpc        0
-php_flag magic_quotes_runtime    0
 php_flag register_globals        0
 php_flag file_uploads            1
 php_flag short_open_tag          1
index 6e69ce4..2890108 100644 (file)
@@ -1167,7 +1167,17 @@ class cm_info implements IteratorAggregate {
      * @return mixed
      */
     public function __call($name, $arguments) {
+        global $CFG;
+
         if (in_array($name, self::$standardmethods)) {
+            if ($CFG->debugdeveloper) {
+                if ($alternative = array_search($name, self::$standardproperties)) {
+                    // All standard methods do not have arguments anyway.
+                    debugging("cm_info::$name() is deprecated, please use the property cm_info->$alternative instead.", DEBUG_DEVELOPER);
+                } else {
+                    debugging("cm_info::$name() is deprecated and should not be used.", DEBUG_DEVELOPER);
+                }
+            }
             // All standard methods do not have arguments anyway.
             return $this->$name();
         }
index f6915be..4ae18b2 100644 (file)
@@ -1860,13 +1860,13 @@ class global_navigation extends navigation_node {
                 $activity->hidden = (!$cm->visible);
                 $activity->modname = $cm->modname;
                 $activity->nodetype = navigation_node::NODETYPE_LEAF;
-                $activity->onclick = $cm->get_on_click();
-                $url = $cm->get_url();
+                $activity->onclick = $cm->onclick;
+                $url = $cm->url;
                 if (!$url) {
                     $activity->url = null;
                     $activity->display = false;
                 } else {
-                    $activity->url = $cm->get_url()->out();
+                    $activity->url = $url->out();
                     $activity->display = $cm->uservisible ? true : false;
                     if (self::module_extends_navigation($cm->modname)) {
                         $activity->nodetype = navigation_node::NODETYPE_BRANCH;
@@ -2011,7 +2011,7 @@ class global_navigation extends navigation_node {
         } else {
             $icon = new pix_icon('icon', get_string('modulename', $cm->modname), $cm->modname);
         }
-        $url = $cm->get_url();
+        $url = $cm->url;
         $activitynode = $coursenode->add(format_string($cm->name), $url, navigation_node::TYPE_ACTIVITY, null, $cm->id, $icon);
         $activitynode->title(get_string('modulename', $cm->modname));
         $activitynode->hidden = (!$cm->visible);
@@ -4317,6 +4317,12 @@ class settings_navigation extends navigation_node {
             $categorynode->add(get_string('filters', 'admin'), $url, self::TYPE_SETTING, null, 'filters', new pix_icon('i/filter', ''));
         }
 
+        // Restore.
+        if (has_capability('moodle/course:create', $this->context)) {
+            $url = new moodle_url('/backup/restorefile.php', array('contextid' => $this->context->id));
+            $categorynode->add(get_string('restorecourse', 'admin'), $url, self::TYPE_SETTING, null, 'restorecourse', new pix_icon('i/restore', ''));
+        }
+
         return $categorynode;
     }
 
index fa07895..6c73fdd 100644 (file)
@@ -226,6 +226,20 @@ class page_requirements_manager {
             )
         ));
 
+        $this->YUI_config->add_group('gallery', array(
+            'name' => 'gallery',
+            'base' => $CFG->httpswwwroot . '/lib/yuilib/gallery/',
+            'combine' => $this->yui3loader->combine,
+            'comboBase' => $CFG->httpswwwroot . '/theme/yui_combo.php' . $sep,
+            'ext' => false,
+            'root' => 'gallery/' . $jsrev . '/',
+            'patterns' => array(
+                'gallery-' => array(
+                    'group' => 'gallery',
+                )
+            )
+        ));
+
         // Set some more loader options applying to groups too.
         if ($CFG->debugdeveloper) {
             // When debugging is enabled, we want to load the non-minified (RAW) versions of YUI library modules rather
@@ -616,20 +630,6 @@ class page_requirements_manager {
         return $output;
     }
 
-    /**
-     * This method was used to load YUI2 libraries into global scope,
-     * use YUI 2in3 instead. Every YUI2 module is represented as a yui2-*
-     * sandboxed module in YUI3 code via Y.YUI2. property.
-     *
-     * {@see http://tracker.moodle.org/browse/MDL-34741}
-     *
-     * @param string|array $libname
-     * @deprecated since 2.4
-     */
-    public function yui2_lib($libname) {
-        throw new coding_exception('PAGE->yui2_lib() is not available any more, use YUI 2in3 instead, see MDL-34741 for more information.');
-    }
-
     /**
      * Returns the actual url through which a script is served.
      *
@@ -983,27 +983,19 @@ class page_requirements_manager {
      * @param array|string $modules One or more modules
      * @param string $function The function to call once modules have been loaded
      * @param array $arguments An array of arguments to pass to the function
-     * @param string $galleryversion The gallery version to use
+     * @param string $galleryversion Deprecated: The gallery version to use
      * @param bool $ondomready
      */
     public function yui_module($modules, $function, array $arguments = null, $galleryversion = null, $ondomready = false) {
-        global $CFG;
-
-        if (!$galleryversion) {
-            $galleryversion = '2010.04.08-12-35';
-        }
-
         if (!is_array($modules)) {
             $modules = array($modules);
         }
-        if (empty($CFG->useexternalyui)) {
-            // We need to set the M.yui.galleryversion to the correct version
-            $jscode = 'M.yui.galleryversion='.json_encode($galleryversion).';';
-        } else {
-            // Set Y's config.gallery to the version
-            $jscode = 'Y.config.gallery='.json_encode($galleryversion).';';
+
+        if ($galleryversion != null) {
+            debugging('The galleryversion parameter to yui_module has been deprecated since Moodle 2.3.');
         }
-        $jscode .= 'Y.use('.join(',', array_map('json_encode', convert_to_array($modules))).',function() {'.js_writer::function_call($function, $arguments).'});';
+
+        $jscode = 'Y.use('.join(',', array_map('json_encode', convert_to_array($modules))).',function() {'.js_writer::function_call($function, $arguments).'});';
         if ($ondomready) {
             $jscode = "Y.on('domready', function() { $jscode });";
         }
index 17157bb..b634aba 100644 (file)
@@ -355,21 +355,15 @@ function rss_add_items($items) {
 }
 
 /**
- * This function return all the common footers for every rss feed in the site
+ * This function return all the common footers for every rss feed in the site.
  *
- * @param string $title       Not used at all
- * @param string $link        Not used at all
- * @param string $description Not used at all
- * @todo  MDL-31050 Fix/Remove this function
  * @return string
  */
-function rss_standard_footer($title = NULL, $link = NULL, $description = NULL) {
+function rss_standard_footer() {
     $status = true;
     $result = '';
 
-    //Close the chanel
     $result .= rss_end_tag('channel', 1, true);
-    ////Close the rss tag
     $result .= '</rss>';
 
     return $result;
index f1d3054..efe09bd 100644 (file)
@@ -696,39 +696,6 @@ ini_set('pcre.backtrack_limit', 20971520);  // 20 MB
 $CFG->wordlist = $CFG->libdir .'/wordlist.txt';
 $CFG->moddata  = 'moddata';
 
-// A hack to get around magic_quotes_gpc being turned on
-// It is strongly recommended to disable "magic_quotes_gpc"!
-if (ini_get_bool('magic_quotes_gpc')) {
-    function stripslashes_deep($value) {
-        $value = is_array($value) ?
-                array_map('stripslashes_deep', $value) :
-                stripslashes($value);
-        return $value;
-    }
-    $_POST = array_map('stripslashes_deep', $_POST);
-    $_GET = array_map('stripslashes_deep', $_GET);
-    $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
-    $_REQUEST = array_map('stripslashes_deep', $_REQUEST);
-    if (!empty($_SERVER['REQUEST_URI'])) {
-        $_SERVER['REQUEST_URI'] = stripslashes($_SERVER['REQUEST_URI']);
-    }
-    if (!empty($_SERVER['QUERY_STRING'])) {
-        $_SERVER['QUERY_STRING'] = stripslashes($_SERVER['QUERY_STRING']);
-    }
-    if (!empty($_SERVER['HTTP_REFERER'])) {
-        $_SERVER['HTTP_REFERER'] = stripslashes($_SERVER['HTTP_REFERER']);
-    }
-   if (!empty($_SERVER['PATH_INFO'])) {
-        $_SERVER['PATH_INFO'] = stripslashes($_SERVER['PATH_INFO']);
-    }
-    if (!empty($_SERVER['PHP_SELF'])) {
-        $_SERVER['PHP_SELF'] = stripslashes($_SERVER['PHP_SELF']);
-    }
-    if (!empty($_SERVER['PATH_TRANSLATED'])) {
-        $_SERVER['PATH_TRANSLATED'] = stripslashes($_SERVER['PATH_TRANSLATED']);
-    }
-}
-
 // neutralise nasty chars in PHP_SELF
 if (isset($_SERVER['PHP_SELF'])) {
     $phppos = strpos($_SERVER['PHP_SELF'], '.php');
@@ -985,9 +952,9 @@ if (PHPUNIT_TEST) {
 
 // // try to detect IE6 and prevent gzip because it is extremely buggy browser
 if (!empty($_SERVER['HTTP_USER_AGENT']) and strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 6') !== false) {
-    @ini_set('zlib.output_compression', 'Off');
+    ini_set('zlib.output_compression', 'Off');
     if (function_exists('apache_setenv')) {
-        @apache_setenv('no-gzip', 1);
+        apache_setenv('no-gzip', 1);
     }
 }
 
index 929ad2e..8c61eeb 100644 (file)
@@ -710,9 +710,6 @@ function setup_validate_php_configuration() {
    if (ini_get_bool('session.auto_start')) {
        print_error('sessionautostartwarning', 'admin');
    }
-   if (ini_get_bool('magic_quotes_runtime')) {
-       print_error('fatalmagicquotesruntime', 'admin');
-   }
 }
 
 /**
@@ -994,11 +991,6 @@ function workaround_max_input_vars() {
         $values = array();
         parse_str($chunk, $values);
 
-        if (ini_get_bool('magic_quotes_gpc')) {
-            // Use the same logic as lib/setup.php to work around deprecated magic quotes.
-            $values = array_map('stripslashes_deep', $values);
-        }
-
         merge_query_params($_POST, $values);
         merge_query_params($_REQUEST, $values);
     }
index 098cc55..e8389de 100644 (file)
@@ -110,4 +110,104 @@ class core_admintree_testcase extends advanced_testcase {
         $tree = new admin_root(true);
         $tree->add('root', new admin_category('bar', 'Bar'), '');
     }
+
+    /**
+     * Saving of values.
+     */
+    public function test_config_logging() {
+        global $DB;
+        $this->resetAfterTest();
+
+        $DB->delete_records('config_log', array());
+
+        $adminroot = new admin_root(true);
+        $adminroot->add('root', $one = new admin_category('one', 'One'));
+        $page = new admin_settingpage('page', 'Page');
+        $page->add(new admin_setting_configtext('text1', 'Text 1', '', ''));
+        $page->add(new admin_setting_configpasswordunmask('pass1', 'Password 1', '', ''));
+        $adminroot->add('one', $page);
+
+        $this->assertEmpty($DB->get_records('config_log'));
+        $data = array('s__text1'=>'sometext', 's__pass1'=>'');
+        $count = $this->save_config_data($adminroot, $data);
+
+        $this->assertEquals(2, $count);
+        $records = $DB->get_records('config_log', array(), 'id asc');
+        $this->assertCount(2, $records);
+        reset($records);
+        $record = array_shift($records);
+        $this->assertNull($record->plugin);
+        $this->assertSame('text1', $record->name);
+        $this->assertNull($record->oldvalue);
+        $this->assertSame('sometext', $record->value);
+        $record = array_shift($records);
+        $this->assertNull($record->plugin);
+        $this->assertSame('pass1', $record->name);
+        $this->assertNull($record->oldvalue);
+        $this->assertSame('', $record->value);
+
+        $DB->delete_records('config_log', array());
+        $data = array('s__text1'=>'other', 's__pass1'=>'nice password');
+        $count = $this->save_config_data($adminroot, $data);
+
+        $this->assertEquals(2, $count);
+        $records = $DB->get_records('config_log', array(), 'id asc');
+        $this->assertCount(2, $records);
+        reset($records);
+        $record = array_shift($records);
+        $this->assertNull($record->plugin);
+        $this->assertSame('text1', $record->name);
+        $this->assertSame('sometext', $record->oldvalue);
+        $this->assertSame('other', $record->value);
+        $record = array_shift($records);
+        $this->assertNull($record->plugin);
+        $this->assertSame('pass1', $record->name);
+        $this->assertSame('', $record->oldvalue);
+        $this->assertSame('********', $record->value);
+
+        $DB->delete_records('config_log', array());
+        $data = array('s__text1'=>'', 's__pass1'=>'');
+        $count = $this->save_config_data($adminroot, $data);
+
+        $this->assertEquals(2, $count);
+        $records = $DB->get_records('config_log', array(), 'id asc');
+        $this->assertCount(2, $records);
+        reset($records);
+        $record = array_shift($records);
+        $this->assertNull($record->plugin);
+        $this->assertSame('text1', $record->name);
+        $this->assertSame('other', $record->oldvalue);
+        $this->assertSame('', $record->value);
+        $record = array_shift($records);
+        $this->assertNull($record->plugin);
+        $this->assertSame('pass1', $record->name);
+        $this->assertSame('********', $record->oldvalue);
+        $this->assertSame('', $record->value);
+    }
+
+    protected function save_config_data(admin_root $adminroot, array $data) {
+        $adminroot->errors = array();
+
+        $settings = admin_find_write_settings($adminroot, $data);
+
+        $count = 0;
+        foreach ($settings as $fullname=>$setting) {
+            /** @var $setting admin_setting */
+            $original = $setting->get_setting();
+            $error = $setting->write_setting($data[$fullname]);
+            if ($error !== '') {
+                $adminroot->errors[$fullname] = new stdClass();
+                $adminroot->errors[$fullname]->data  = $data[$fullname];
+                $adminroot->errors[$fullname]->id    = $setting->get_id();
+                $adminroot->errors[$fullname]->error = $error;
+            } else {
+                $setting->write_setting_flags($data);
+            }
+            if ($setting->post_write_settings($original)) {
+                $count++;
+            }
+        }
+
+        return $count;
+    }
 }
index 1abab2d..83b9daf 100644 (file)
@@ -657,4 +657,42 @@ class core_modinfolib_testcase extends advanced_testcase {
         $this->assertFalse($cm->uservisible);
         $this->assertTrue($cm->is_user_access_restricted_by_capability());
     }
+
+    /**
+     * Tests that various deprecated cm_info methods are throwing debuggign messages
+     */
+    public function test_cm_info_property_deprecations() {
+        global $DB, $CFG;
+
+        $this->resetAfterTest();
+
+        $course = $this->getDataGenerator()->create_course( array('format' => 'topics', 'numsections' => 3),
+                array('createsections' => true));
+        $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
+        $cm = get_fast_modinfo($course->id)->instances['forum'][$forum->id];
+
+        $cm->get_url();
+        $this->assertDebuggingCalled('cm_info::get_url() is deprecated, please use the property cm_info->url instead.');
+
+        $cm->get_content();
+        $this->assertDebuggingCalled('cm_info::get_content() is deprecated, please use the property cm_info->content instead.');
+
+        $cm->get_extra_classes();
+        $this->assertDebuggingCalled('cm_info::get_extra_classes() is deprecated, please use the property cm_info->extraclasses instead.');
+
+        $cm->get_on_click();
+        $this->assertDebuggingCalled('cm_info::get_on_click() is deprecated, please use the property cm_info->onclick instead.');
+
+        $cm->get_custom_data();
+        $this->assertDebuggingCalled('cm_info::get_custom_data() is deprecated, please use the property cm_info->customdata instead.');
+
+        $cm->get_after_link();
+        $this->assertDebuggingCalled('cm_info::get_after_link() is deprecated, please use the property cm_info->afterlink instead.');
+
+        $cm->get_after_edit_icons();
+        $this->assertDebuggingCalled('cm_info::get_after_edit_icons() is deprecated, please use the property cm_info->afterediticons instead.');
+
+        $cm->obtain_dynamic_data();
+        $this->assertDebuggingCalled('cm_info::obtain_dynamic_data() is deprecated and should not be used.');
+    }
 }
index 8718534..1cdd34b 100644 (file)
@@ -492,4 +492,43 @@ class core_weblib_testcase extends advanced_testcase {
         $this->assertEquals(DEBUG_NONE, $CFG->debug);
         $this->assertFalse($CFG->debugdeveloper);
     }
+
+    public function test_strip_pluginfile_content() {
+        $source = <<<SOURCE
+Hello!
+
+I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness.
+
+URL outside a tag: https://moodle.org/logo/logo-240x60.gif
+Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif
+
+External link 1:<img src='https://moodle.org/logo/logo-240x60.gif' alt='Moodle'/>
+External link 2:<img alt="Moodle" src="https://moodle.org/logo/logo-240x60.gif"/>
+Internal link 1:<img src='@@PLUGINFILE@@/logo-240x60.gif' alt='Moodle'/>
+Internal link 2:<img alt="Moodle" src="@@PLUGINFILE@@logo-240x60.gif"/>
+Anchor link 1:<a href="@@PLUGINFILE@@logo-240x60.gif" alt="bananas">Link text</a>
+Anchor link 2:<a title="bananas" href="../logo-240x60.gif">Link text</a>
+Anchor + ext. img:<a title="bananas" href="../logo-240x60.gif"><img alt="Moodle" src="@@PLUGINFILE@@logo-240x60.gif"/></a>
+Ext. anchor + img:<a href="@@PLUGINFILE@@logo-240x60.gif"><img alt="Moodle" src="https://moodle.org/logo/logo-240x60.gif"/></a>
+SOURCE;
+        $expected = <<<EXPECTED
+Hello!
+
+I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness.
+
+URL outside a tag: https://moodle.org/logo/logo-240x60.gif
+Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif
+
+External link 1:<img src="https://moodle.org/logo/logo-240x60.gif" alt="Moodle" />
+External link 2:<img alt="Moodle" src="https://moodle.org/logo/logo-240x60.gif" />
+Internal link 1:
+Internal link 2:
+Anchor link 1:Link text
+Anchor link 2:<a title="bananas" href="../logo-240x60.gif">Link text</a>
+Anchor + ext. img:<a title="bananas" href="../logo-240x60.gif"></a>
+Ext. anchor + img:<img alt="Moodle" src="https://moodle.org/logo/logo-240x60.gif" />
+EXPECTED;
+        $this->assertSame($expected, strip_pluginfile_content($source));
+    }
+
 }
index b24bfc5..ed5ce6a 100644 (file)
     <version>3.13.0</version>
     <licenseversion></licenseversion>
   </library>
+  <library>
+    <location>yuilib/gallery</location>
+    <name>YUI Gallery</name>
+    <license>BSD</license>
+    <version>gallery-2013.10.02-20-26</version>
+    <licenseversion></licenseversion>
+  </library>
   <library>
     <location>jquery</location>
     <name>jQuery</name>
index a160016..afc80e3 100644 (file)
@@ -11,6 +11,8 @@ DEPRECATIONS:
 * mod_feedback\event\instances_list_viewed has been deprecated. Please use mod_feedback\event\course_module_instance_list_viewed instead.
 * mod_page\event\instances_list_viewed has been deprecated. Please use mod_page\event\course_module_instance_list_viewed instead.
 * The constants FRONTPAGECOURSELIST, FRONTPAGETOPICONLY & FRONTPAGECOURSELIMIT have been removed.
+* Various cm_info methods have been deprecated in favour of their read-only properties (get_url(), get_content(), get_extra_classes(),
+  get_on_click(), get_custom_data(), get_after_link, get_after_edit_icons)
 
 YUI:
   * The lightbox attribute for moodle-core-notification-dialogue has been
index c499f46..a5780b0 100644 (file)
@@ -1523,6 +1523,25 @@ function format_module_intro($module, $activity, $cmid, $filter=true) {
     return trim(format_text($intro, $activity->introformat, $options, null));
 }
 
+/**
+ * Removes the usage of Moodle files from a text.
+ *
+ * In some rare cases we need to re-use a text that already has embedded links
+ * to some files hosted within Moodle. But the new area in which we will push
+ * this content does not support files... therefore we need to remove those files.
+ *
+ * @param string $source The text
+ * @return string The stripped text
+ */
+function strip_pluginfile_content($source) {
+    $baseurl = '@@PLUGINFILE@@';
+    // Looking for something like < .* "@@pluginfile@@.*" .* >
+    $pattern = '$<[^<>]+["\']' . $baseurl . '[^"\']*["\'][^<>]*>$';
+    $stripped = preg_replace($pattern, '', $source);
+    // Use purify html to rebalence potentially mismatched tags and generally cleanup.
+    return purify_html($stripped);
+}
+
 /**
  * Legacy function, used for cleaning of old forum and glossary text only.
  *
@@ -2550,6 +2569,7 @@ function redirect($url, $message='', $delay=-1) {
     if ($PAGE) {
         $PAGE->set_context(null);
         $PAGE->set_pagelayout('redirect');  // No header and footer needed.
+        $PAGE->set_title(get_string('pageshouldredirect', 'moodle'));
     }
 
     if ($url instanceof moodle_url) {
index a765037..fb3e3e5 100644 (file)
Binary files a/lib/yui/build/moodle-core-blocks/moodle-core-blocks-debug.js and b/lib/yui/build/moodle-core-blocks/moodle-core-blocks-debug.js differ
index 4da7627..9699956 100644 (file)
Binary files a/lib/yui/build/moodle-core-blocks/moodle-core-blocks-min.js and b/lib/yui/build/moodle-core-blocks/moodle-core-blocks-min.js differ
index 2b3315f..a1c7810 100644 (file)
Binary files a/lib/yui/build/moodle-core-blocks/moodle-core-blocks.js and b/lib/yui/build/moodle-core-blocks/moodle-core-blocks.js differ
index 31d81fc..03408fe 100644 (file)
Binary files a/lib/yui/build/moodle-core-tooltip/moodle-core-tooltip-debug.js and b/lib/yui/build/moodle-core-tooltip/moodle-core-tooltip-debug.js differ
index e99b50a..c31276b 100644 (file)
Binary files a/lib/yui/build/moodle-core-tooltip/moodle-core-tooltip-min.js and b/lib/yui/build/moodle-core-tooltip/moodle-core-tooltip-min.js differ
index 31d81fc..03408fe 100644 (file)
Binary files a/lib/yui/build/moodle-core-tooltip/moodle-core-tooltip.js and b/lib/yui/build/moodle-core-tooltip/moodle-core-tooltip.js differ
index 4e13157..3e2c6fe 100644 (file)
@@ -27,7 +27,7 @@ BLOCKREGION.prototype = {
         Y.log('Block region `'+this.get('region')+'` initialising', 'info');
         if (!node) {
             Y.log('block region known about but no HTML structure found for it. Guessing structure.', 'warn');
-            this.create_and_add_node();
+            node = this.create_and_add_node();
         }
         var body = Y.one('body'),
             hasblocks = node.all('.'+CSS.BLOCK).size() > 0,
@@ -43,6 +43,7 @@ BLOCKREGION.prototype = {
      * Creates a generic block region node and adds it to the DOM at the best guess location.
      * Any calling of this method is an unfortunate circumstance.
      * @method create_and_add_node
+     * @return Node The newly created Node
      */
     create_and_add_node : function() {
         var c = Y.Node.create,
@@ -85,6 +86,8 @@ BLOCKREGION.prototype = {
             Y.one('body').append(node);
         }
         this.set('node', node);
+
+        return node;
     },
 
     /**
index 2f19a8c..1812cb4 100644 (file)
@@ -377,11 +377,17 @@ Y.extend(TOOLTIP, M.core.dialogue, {
             responseobject = Y.JSON.parse(response);
             if (responseobject.error) {
                 this.close_panel();
-                return new M.core.ajaxException(responseobject);
+                Y.use('moodle-core-notification-ajaxexception', function() {
+                    return new M.core.ajaxException(responseobject).show();
+                });
+                return this;
             }
         } catch (error) {
             this.close_panel();
-            return new M.core.exception(error);
+            Y.use('moodle-core-notification-exception', function() {
+                return new M.core.exception(error).show();
+            });
+            return this;
         }
 
         // Set the contents using various handlers.
index 97bf152..5e3f977 100644 (file)
@@ -4,7 +4,7 @@
         "base",
         "node",
         "io-base",
-        "moodle-core-notification",
+        "moodle-core-notification-dialogue",
         "json-parse",
         "widget-position",
         "widget-position-align",
@@ -55,12 +55,9 @@ Sortable.prototype._afterSort = function (e) {
     if (node.isRoot()) {
         this.render();
     } else {
-        this.renderNode(node, {
-            force         : true,
-            renderChildren: true
-        });
+        this.renderNode(node, {renderChildren: true});
     }
 };
 
 
-}, '@VERSION@', {"requires": ["gallery-sm-treeview", "tree-sortable"]});
+}, 'gallery-2013.06.20-02-07', {"requires": ["gallery-sm-treeview", "tree-sortable"]});
diff --git a/lib/yuilib/gallery/gallery-sm-treeview-sortable/gallery-sm-treeview-sortable-min.js b/lib/yuilib/gallery/gallery-sm-treeview-sortable/gallery-sm-treeview-sortable-min.js
new file mode 100644 (file)
index 0000000..b72a22f
--- /dev/null
@@ -0,0 +1 @@
+YUI.add("gallery-sm-treeview-sortable",function(e,t){var n=e.TreeView.Sortable=function(){};e.mix(n.prototype,e.Tree.Sortable.prototype),n.prototype._attachTreeViewEvents=function(){e.TreeView.prototype._attachTreeViewEvents.call(this),this._treeViewEvents.push(this.after("sort",this._afterSort))},n.prototype._afterSort=function(e){var t=e.node;if(!this.rendered||!t.state.renderedChildren)return;t.isRoot()?this.render():this.renderNode(t,{renderChildren:!0})}},"gallery-2013.06.20-02-07",{requires:["gallery-sm-treeview","tree-sortable"]});
diff --git a/lib/yuilib/gallery/gallery-sm-treeview-sortable/gallery-sm-treeview-sortable.js b/lib/yuilib/gallery/gallery-sm-treeview-sortable/gallery-sm-treeview-sortable.js
new file mode 100644 (file)
index 0000000..efda7c8
--- /dev/null
@@ -0,0 +1,63 @@
+YUI.add('gallery-sm-treeview-sortable', function (Y, NAME) {
+
+/**
+Provides `Y.TreeView.Sortable`, a `Y.TreeView` extension that mixes in
+`Y.Tree.Sortable` and provides related TreeView-specific functionality.
+
+@module gallery-sm-treeview
+@submodule gallery-sm-treeview-sortable
+**/
+
+/**
+Extension for `Y.TreeView` that mixes in `Y.Tree.Sortable` and provides related
+TreeView-specific functionality (such as re-rendering a node after it's sorted).
+
+@class TreeView.Sortable
+@constructor
+@extensionfor TreeView
+@extends Tree.Sortable
+**/
+
+var Sortable = Y.TreeView.Sortable = function () {};
+
+Y.mix(Sortable.prototype, Y.Tree.Sortable.prototype);
+
+// -- Protected Methods ----------------------------------------------------
+
+// Overrides Y.TreeView#_attachTreeViewEvents().
+Sortable.prototype._attachTreeViewEvents = function () {
+    Y.TreeView.prototype._attachTreeViewEvents.call(this);
+
+    this._treeViewEvents.push(
+        this.after('sort', this._afterSort)
+    );
+};
+
+// -- Event Handlers -------------------------------------------------------
+
+/**
+Re-renders a node if necessary after a `sort` event.
+
+@method _afterSort
+@param {EventFacade} e
+@protected
+**/
+Sortable.prototype._afterSort = function (e) {
+    var node = e.node;
+
+    // If this tree hasn't been rendered yet or the sorted node's children
+    // haven't been rendered yet, there's nothing to do.
+    if (!this.rendered || !node.state.renderedChildren) {
+        return;
+    }
+
+    // Re-render the sorted node and its children.
+    if (node.isRoot()) {
+        this.render();
+    } else {
+        this.renderNode(node, {renderChildren: true});
+    }
+};
+
+
+}, 'gallery-2013.06.20-02-07', {"requires": ["gallery-sm-treeview", "tree-sortable"]});
diff --git a/lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates-debug.js b/lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates-debug.js
new file mode 100644 (file)
index 0000000..a9fa76b
--- /dev/null
@@ -0,0 +1,30 @@
+YUI.add('gallery-sm-treeview-templates', function (Y, NAME) {
+
+var Micro = Y.Template.Micro;
+
+Y.namespace('TreeView').Templates = {
+    children: Micro.compile(
+        '<ul class="<%= data.classNames.children %>" ' +
+
+            '<% if (data.node.isRoot()) { %>' +
+                'role="tree" tabindex="0"' +
+            '<% } else { %>' +
+                'role="group"' +
+            '<% } %>' +
+
+        '></ul>'
+    ),
+
+    node: Micro.compile(
+        '<li id="<%= data.node.id %>" class="<%= data.nodeClassNames.join(" ") %>" role="treeitem" aria-labelled-by="<%= data.node.id %>-label">' +
+            '<div class="<%= data.classNames.row %>" data-node-id="<%= data.node.id %>">' +
+                '<span class="<%= data.classNames.indicator %>"><s></s></span>' +
+                '<span class="<%= data.classNames.icon %>"></span>' +
+                '<span id="<%= data.node.id %>-label" class="<%= data.classNames.label %>"><%== data.node.label %></span>' +
+            '</div>' +
+        '</li>'
+    )
+};
+
+
+}, 'gallery-2013.03.27-22-06', {"requires": ["template-micro"]});
diff --git a/lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates-min.js b/lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates-min.js
new file mode 100644 (file)
index 0000000..90353fa
--- /dev/null
@@ -0,0 +1 @@
+YUI.add("gallery-sm-treeview-templates",function(e,t){var n=e.Template.Micro;e.namespace("TreeView").Templates={children:n.compile('<ul class="<%= data.classNames.children %>" <% if (data.node.isRoot()) { %>role="tree" tabindex="0"<% } else { %>role="group"<% } %>></ul>'),node:n.compile('<li id="<%= data.node.id %>" class="<%= data.nodeClassNames.join(" ") %>" role="treeitem" aria-labelled-by="<%= data.node.id %>-label"><div class="<%= data.classNames.row %>" data-node-id="<%= data.node.id %>"><span class="<%= data.classNames.indicator %>"><s></s></span><span class="<%= data.classNames.icon %>"></span><span id="<%= data.node.id %>-label" class="<%= data.classNames.label %>"><%== data.node.label %></span></div></li>')}},"gallery-2013.03.27-22-06",{requires:["template-micro"]});
diff --git a/lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates.js b/lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates.js
new file mode 100644 (file)
index 0000000..a9fa76b
--- /dev/null
@@ -0,0 +1,30 @@
+YUI.add('gallery-sm-treeview-templates', function (Y, NAME) {
+
+var Micro = Y.Template.Micro;
+
+Y.namespace('TreeView').Templates = {
+    children: Micro.compile(
+        '<ul class="<%= data.classNames.children %>" ' +
+
+            '<% if (data.node.isRoot()) { %>' +
+                'role="tree" tabindex="0"' +
+            '<% } else { %>' +
+                'role="group"' +
+            '<% } %>' +
+
+        '></ul>'
+    ),
+
+    node: Micro.compile(
+        '<li id="<%= data.node.id %>" class="<%= data.nodeClassNames.join(" ") %>" role="treeitem" aria-labelled-by="<%= data.node.id %>-label">' +
+            '<div class="<%= data.classNames.row %>" data-node-id="<%= data.node.id %>">' +
+                '<span class="<%= data.classNames.indicator %>"><s></s></span>' +
+                '<span class="<%= data.classNames.icon %>"></span>' +
+                '<span id="<%= data.node.id %>-label" class="<%= data.classNames.label %>"><%== data.node.label %></span>' +
+            '</div>' +
+        '</li>'
+    )
+};
+
+
+}, 'gallery-2013.03.27-22-06', {"requires": ["template-micro"]});
@@ -208,14 +208,9 @@ TreeView = Y.Base.create('treeView', Y.View, [
     @method renderChildren
     @param {Tree.Node} treeNode Tree node whose children should be rendered.
     @param {Object} [options] Options.
-
         @param {Node} [options.container] `Y.Node` instance of a container into
             which the children should be rendered. If the container already
             contains rendered children, they will be re-rendered in place.
-
-        @param {Boolean} [options.force=false] If `true`, children will be
-            re-rendered from scratch even if they've already been rendered.
-
     @return {Node} `Y.Node` instance containing the rendered children.
     **/
     renderChildren: function (treeNode, options) {
@@ -225,11 +220,6 @@ TreeView = Y.Base.create('treeView', Y.View, [
             childrenNode = container && container.one('>.' + this.classNames.children),
             lazyRender   = this._lazyRender;
 
-        if (childrenNode && options.force) {
-            childrenNode.remove(true);
-            childrenNode = null;
-        }
-
         if (!childrenNode) {
             childrenNode = Y.Node.create(this.templates.children({
                 classNames: this.classNames,
@@ -271,17 +261,10 @@ TreeView = Y.Base.create('treeView', Y.View, [
     @method renderNode
     @param {Tree.Node} treeNode Tree node to render.
     @param {Object} [options] Options.
-
         @param {Node} [options.container] `Y.Node` instance of a container to
             which the rendered tree node should be appended.
-
-        @param {Boolean} [options.force=false] If `true`, this node (and its
-            children if `renderChildren` is `true`) will be re-rendered from
-            scratch, even if it's already been rendered.
-
         @param {Boolean} [options.renderChildren=false] Whether or not to render
             this node's children.
-
     @return {Node} `Y.Node` instance of the rendered tree node.
     **/
     renderNode: function (treeNode, options) {
@@ -290,9 +273,7 @@ TreeView = Y.Base.create('treeView', Y.View, [
         var classNames     = this.classNames,
             hasChildren    = treeNode.hasChildren(),
             htmlNode       = treeNode._htmlNode,
-            oldHtmlNode    = options.force && htmlNode,
             nodeClassNames = {},
-
             className;
 
         // Build the hash of CSS classes for this node.
@@ -300,7 +281,7 @@ TreeView = Y.Base.create('treeView', Y.View, [
         nodeClassNames[classNames.canHaveChildren] = !!treeNode.canHaveChildren;
         nodeClassNames[classNames.hasChildren]     = hasChildren;
 
-        if (htmlNode && !options.force) {
+        if (htmlNode) {
             // This node has already been rendered, so we just need to update
             // the DOM instead of re-rendering it from scratch.
             htmlNode.one('.' + classNames.label).setHTML(treeNode.label);
@@ -311,8 +292,7 @@ TreeView = Y.Base.create('treeView', Y.View, [
                 }
             }
         } else {
-            // This node hasn't been rendered yet or is being forcibly
-            // re-rendered.
+            // This node hasn't been rendered yet, so render it from scratch.
             var enabledClassNames = [];
 
             for (className in nodeClassNames) {
@@ -350,13 +330,8 @@ TreeView = Y.Base.create('treeView', Y.View, [
 
         treeNode.state.rendered = true;
 
-        if (options.force) {
-            oldHtmlNode.replace(htmlNode);
-            oldHtmlNode.destroy();
-        } else {
-            if (options.container && htmlNode.get('parentNode') !== options.container) {
-                options.container.append(htmlNode);
-            }
+        if (options.container) {
+            options.container.append(htmlNode);
         }
 
         return htmlNode;
@@ -725,7 +700,7 @@ TreeView = Y.Base.create('treeView', Y.View, [
 Y.TreeView = Y.mix(TreeView, Y.TreeView);
 
 
-}, '@VERSION@', {
+}, 'gallery-2013.06.20-02-07', {
     "requires": [
         "base-build",
         "classnamemanager",
diff --git a/lib/yuilib/gallery/gallery-sm-treeview/gallery-sm-treeview-min.js b/lib/yuilib/gallery/gallery-sm-treeview/gallery-sm-treeview-min.js
new file mode 100644 (file)
index 0000000..0a2e306
--- /dev/null
@@ -0,0 +1,2 @@
+YUI.add("gallery-sm-treeview",function(e,t){var n=e.Template.Micro;e.namespace("TreeView").Templates={children:n.compile('<ul class="<%= data.classNames.children %>" <% if (data.node.isRoot()) { %>role="tree" tabindex="0"<% } else { %>role="group"<% } %>></ul>'),node:n.compile('<li id="<%= data.node.id %>" class="<%= data.nodeClassNames.join(" ") %>" role="treeitem" aria-labelled-by="<%= data.node.id %>-label"><div class="<%= data.classNames.row %>" data-node-id="<%= data.node.id %>"><span class="<%= data.classNames.indicator %>"><s></s></span><span class="<%= data.classNames.icon %>"></span><span id="<%= data.node.id %>-label" class="<%= data.classNames.label %>"><%== data.node.label %></span></div></li>')};var r=e.ClassNameManager.getClassName,i=e.Base.create("treeView",e.View,[e.Tree,e.Tree.Labelable,e.Tree.Openable,e.Tree.Selectable],{classNames:{canHaveChildren:r("treeview-can-have-children"),children:r("treeview-children"),hasChildren:r("treeview-has-children"),icon:r("treeview-icon"),indicator:r("treeview-indicator"),label:r("treeview-label"),node:r("treeview-node"),noTouch:r("treeview-notouch"),open:r("treeview-open"),row:r("treeview-row"),selected:r("treeview-selected"),touch:r("treeview-touch"),treeview:r("treeview")},rendered:!1,templates:e.TreeView.Templates,_isYUITreeView:!0,initializer:function(t){t&&t.templates&&(this.templates=e.merge(this.templates,t.templates)),this._renderQueue={},this._attachTreeViewEvents()},destructor:function(){clearTimeout(this._renderTimeout),this._detachTreeViewEvents(),this._renderQueue=null},destroyNode:function(t,n){return t._htmlNode=null,e.Tree.prototype.destroyNode.call(this,t,n)},getHTMLNode:function(e){return e._htmlNode||(e._htmlNode=this.get("container").one("#"+e.id)),e._htmlNode},render:function(){var t=this.get("container"),n="ontouchstart"in e.config.win;return t.addClass(this.classNames.treeview),t.addClass(this.classNames[n?"touch":"noTouch"]),this._childrenNode=this.renderChildren(this.rootNode,{container:t}),t.inDoc()||e.one("body").append(t),this.rendered=!0,this},renderChildren:function(t,n){n||(n={});var r=n.container,i=r&&r.one(">."+this.classNames.children),s=this._lazyRender;i||(i=e.Node.create(this.templates.children({classNames:this.classNames,node:t,treeview:this})));if(t.hasChildren()){i.set("aria-expanded",t.isOpen());for(var o=0,u=t.children.length;o<u;o++){var a=t.children[o];this.renderNode(a,{container:i,renderChildren:!s||a.isOpen()})}}return t.state.renderedChildren=!0,r&&r.append(i),i},renderNode:function(t,n){n||(n={});var r=this.classNames,i=t.hasChildren(),s=t._htmlNode,o={},u;o[r.node]=!0,o[r.canHaveChildren]=!!t.canHaveChildren,o[r.hasChildren]=i;if(s){s.one("."+r.label).setHTML(t.label);for(u in o)o.hasOwnProperty(u)&&s.toggleClass(u,o[u])}else{var a=[];for(u in o)o.hasOwnProperty(u)&&o[u]&&a.push(u);s=t._htmlNode=e.Node.create(this.templates.node({classNames:r,nodeClassNames:a,node:t,treeview:this}))}this._syncNodeOpenState(t,s),this._syncNodeSelectedState(t,s);if(i)n.renderChildren&&this.renderChildren(t,{container:s});else{var f=s.one(">."+r.children);f&&f.remove(!0)}return t.state.rendered=!0,n.container&&n.container.append(s),s},_attachTreeViewEvents:function(){this._treeViewEvents||(this._treeViewEvents=[]);var e=this.classNames,t=this.get("container");this._treeViewEvents.push(this.after({add:this._afterAdd,clear:this._afterClear,close:this._afterClose,multiSelectChange:this._afterTreeViewMultiSelectChange,open:this._afterOpen,remove:this._afterRemove,select:this._afterSelect,unselect:this._afterUnselect}),t.on("mousedown",this._onMouseDown,this),t.delegate("click",this._onIndicatorClick,"."+e.indicator,this),t.delegate("click",this._onRowClick,"."+e.row,this),t.delegate("dblclick",this._onRowDoubleClick,"."+e.canHaveChildren+" > ."+e.row,this))},_detachTreeViewEvents:function(){(new e.EventHandle(this._treeViewEvents)).detach()},_processRenderQueue:function(){if(!this.rendered)return;var e=this._renderQueue,t;for(var n in e)e.hasOwnProperty(n)&&(t=this.getNodeById(n),t&&this.renderNode(t,e[n]));this._renderQueue={}},_queueRender:function(t,n){if(!this.rendered)return;var r=this._renderQueue,i=this;return clearTimeout(this._renderTimeout),r[t.id]=e.merge(r[t.id],n),this._renderTimeout=setTimeout(function(){i._processRenderQueue()},15),this},_setLazyRender:function(e){return this._lazyRender=e},_syncNodeOpenState:function(e,t){t||(t=this.getHTMLNode(e));if(!t)return;e.isOpen()?t.addClass(this.classNames.open).set("aria-expanded",!0):t.removeClass(this.classNames.open).set("aria-expanded",!1)},_syncNodeSelectedState:function(e,t){t||(t=this.getHTMLNode(e));if(!t)return;var n=this.get("multiSelect");e.isSelected()?(t.addClass(this.classNames.selected),n?t.set("aria-selected",!0):t.set("tabIndex",0)):(t.removeClass(this.classNames.selected).removeAttribute("tabIndex"),n&&t.set("aria-selected",!1))},_afterAdd:function(e){if(!this.rendered)return;var t=e.parent,n=t.isRoot(),r=e.node,i,s;n?i=this._childrenNode:(s=this.getHTMLNode(t),i=s&&s.one(">."+this.classNames.children)),i?(i.insert(this.renderNode(r,{renderChildren:!this._lazyRender||r.isOpen()}),e.index),n||this._queueRender(t)):n||this._queueRender(t,{renderChildren:!0})},_afterClear:function(){if(!this.rendered)return;clearTimeout(this._renderTimeout),this._renderQueue={},delete this._childrenNode,this.rendered=!1,this.get("container").empty(),this.render()},_afterClose:function(e){this.rendered&&this._syncNodeOpenState(e.node)},_afterOpen:function(e){if(!this.rendered)return;var t=e.node,n=this.getHTMLNode(t);t.state.renderedChildren||this.renderChildren(t,{container:n}),this._syncNodeOpenState(t,n)},_afterRemove:function(e){if(!this.rendered)return;var t=e.node,n=e.parent;this._renderQueue[t.id]&&delete this._renderQueue[t.id];var r=this.getHTMLNode(t);r&&(r.empty().remove(!0),t._htmlNode=null),t.state.destroyed||t.traverse(function(e){e._htmlNode=null,e.state.rendered=!1,e.state.renderedChildren=!1}),n&&!n.hasChildren()&&this.renderNode(n)},_afterSelect
+:function(e){this.rendered&&this._syncNodeSelectedState(e.node)},_afterTreeViewMultiSelectChange:function(e){if(!this.rendered)return;var t=this.get("container"),n=t.one("> ."+this.classNames.children),r=t.all("."+this.classNames.node);e.newVal?(n.set("aria-multiselectable",!0),r.set("aria-selected",!1)):(n.removeAttribute("aria-multiselectable"),r.removeAttribute("aria-selected"))},_afterUnselect:function(e){this.rendered&&this._syncNodeSelectedState(e.node)},_onIndicatorClick:function(e){var t=e.currentTarget.ancestor("."+this.classNames.row);e.stopImmediatePropagation(),this.getNodeById(t.getData("node-id")).toggleOpen()},_onMouseDown:function(e){e.preventDefault()},_onRowClick:function(e){if(e.button>1)return;var t=this.getNodeById(e.currentTarget.getData("node-id"));this.get("multiSelect")?t[t.isSelected()?"unselect":"select"]():t.select()},_onRowDoubleClick:function(e){if(e.button>1)return;this.getNodeById(e.currentTarget.getData("node-id")).toggleOpen()}},{ATTRS:{lazyRender:{lazyAdd:!1,setter:"_setLazyRender",value:!0}}});e.TreeView=e.mix(i,e.TreeView)},"gallery-2013.06.20-02-07",{requires:["base-build","classnamemanager","template-micro","tree","tree-labelable","tree-openable","tree-selectable","view"],skinnable:!0});
similarity index 94%
rename from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/moodle-mod_scorm-treeview-sortable-debug.js
rename to lib/yuilib/gallery/gallery-sm-treeview/gallery-sm-treeview.js
index 796207c..d65f31f 100644 (file)
Binary files a/mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/moodle-mod_scorm-treeview-sortable-debug.js and b/lib/yuilib/gallery/gallery-sm-treeview/gallery-sm-treeview.js differ
index 25dd241..7c7a058 100644 (file)
@@ -12,5 +12,14 @@ Description of import of various YUI libraries into Moodle:
 * update lib/thrirdpartylibs.xml
 * verify our simpleyui rollup contents in /theme/yui_combo.php
 
+3/ YUI3 Gallery version gallery-2013.10.02-20-26:
+* selective copy of the "build" directory for the checked out tag of yui3-gallery.
+  Unit test code coverage files (*-coverage.js) are removed but no other changes are made.
+* update lib/thirdpartylibs.xml
+* Note: versions in the gallery modules may differ from the tagged version but will be the
+  latest at the time the module was tagged.
+Currently supported gallery modules:
+* gallery-sm-treeview*
+
 Code downloaded from:
 http://yuilibrary.com
index 7c67ad9..5e7d6e8 100644 (file)
@@ -29,6 +29,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * mod_assign assessable submitted event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type bool submission_editable is submission editable.
+ * }
+ *
  * @package    mod_assign
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 2596e9b..616005d 100644 (file)
@@ -29,6 +29,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * mod_assign marker updated event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int markerid userid id of marker.
+ * }
+ *
  * @package    mod_assign
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 731be58..32be18b 100644 (file)
@@ -29,6 +29,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * mod_assign submission status updated event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string newstatus status of submission.
+ * }
+ *
  * @package    mod_assign
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 00c7812..6ccdf0d 100644 (file)
@@ -29,6 +29,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * mod_assign workflow state updated event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string newstatus status of submission.
+ * }
+ *
  * @package    mod_assign
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index a062248..e68af3a 100644 (file)
@@ -143,5 +143,16 @@ $capabilities = array(
         'clonepermissionsfrom' => 'moodle/grade:manage'
     ),
 
+    'mod/assign:viewgrades' => array(
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_MODULE,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW,
+            'teacher' => CAP_ALLOW
+        )
+    ),
+
+
 );
 
index 1f043cb..96dde23 100644 (file)
@@ -214,23 +214,6 @@ class assign_feedback_comments extends assign_feedback_plugin {
         $mform->disabledIf('assignfeedback_comments_commentinline', 'assignfeedback_comments_enabled', 'notchecked');
    }
 
-    /**
-     * A student submission may contain image tags that refer to images stored
-     * in the file area for the submission. We cannot allow these links to be copied to
-     * the feedback text fields, so we must strip them from the content.
-     *
-     * @param string $source The submission text
-     * @return string The stripped text
-     */
-    protected function strip_moodle_content($source) {
-        $baseurl = '@@PLUGINFILE@@';
-        // Looking for something like < .* "@@pluginfile@@.*" .* >
-        $pattern = '$<[^<>]+["\']' . $baseurl . '[^"\']*["\'][^<>]*>$';
-        $stripped = preg_replace($pattern, '', $source);
-        // Use purify html to rebalence potentially mismatched tags and generally cleanup.
-        return purify_html($stripped);
-    }
-
     /**
      * Convert the text from any submission plugin that has an editor field to
      * a format suitable for inserting in the feedback text field.
@@ -247,7 +230,7 @@ class assign_feedback_comments extends assign_feedback_plugin {
             $fields = $plugin->get_editor_fields();
             if ($plugin->is_enabled() && $plugin->is_visible() && !empty($fields)) {
                 foreach ($fields as $key => $description) {
-                    $rawtext = $this->strip_moodle_content($plugin->get_editor_text($key, $submission->id));
+                    $rawtext = strip_pluginfile_content($plugin->get_editor_text($key, $submission->id));
 
                     $newformat = $plugin->get_editor_format($key, $submission->id);
 
index 3ad4571..2d48136 100644 (file)
@@ -89,4 +89,3 @@ $string['unsavedchanges'] = 'Unsaved changes';
 $string['viewfeedbackonline'] = 'View annotated PDF...';
 $string['white'] = 'White';
 $string['yellow'] = 'Yellow';
-$string['zlibnotavailable'] = 'Php extension "zlib" is not available. The annotate PDF feature relies on this php extension and will be disabled until zlib is installed and enabled.';
index bca275c..1df66f3 100644 (file)
@@ -266,9 +266,6 @@ class assign_feedback_editpdf extends assign_feedback_plugin {
      */
     public function is_enabled() {
         $testpath = assignfeedback_editpdf\pdf::test_gs_path();
-        if (!extension_loaded('zlib')) {
-            return false;
-        }
         if ($testpath->status == assignfeedback_editpdf\pdf::GSPATH_OK) {
             return true;
         }
index 7831262..991e57c 100644 (file)
@@ -39,13 +39,6 @@ $settings->add(new admin_setting_configexecutable('assignfeedback_editpdf/gspath
                                                   get_string('gspath_help', 'assignfeedback_editpdf'),
                                                   '/usr/bin/gs'));
 
-$setting = new admin_setting_php_extension_enabled('assignfeedback_editpdf/zlibenabled',
-                                                   get_string('zlibenabled', 'admin'),
-                                                   get_string('zlibnotavailable', 'assignfeedback_editpdf'),
-                                                   'zlib');
-
-$settings->add($setting);
-
 $url = new moodle_url('/mod/assign/feedback/editpdf/testgs.php');
 $link = html_writer::link($url, get_string('testgs', 'assignfeedback_editpdf'));
 $settings->add(new admin_setting_heading('testgs', '', $link));
index 87d0389..5c96c3c 100644 (file)
@@ -52,6 +52,8 @@ class assign_grading_table extends table_sql implements renderable {
     private $quickgrading = false;
     /** @var boolean $hasgrantextension - Only do the capability check once for the entire table */
     private $hasgrantextension = false;
+    /** @var boolean $hasgrade - Only do the capability check once for the entire table */
+    private $hasgrade = false;
     /** @var array $groupsubmissions - A static cache of group submissions */
     private $groupsubmissions = array();
     /** @var array $submissiongroups - A static cache of submission groups */
@@ -83,6 +85,11 @@ class assign_grading_table extends table_sql implements renderable {
         parent::__construct('mod_assign_grading');
         $this->assignment = $assignment;
 
+        // Check permissions up front.
+        $this->hasgrantextension = has_capability('mod/assign:grantextension',
+                                                  $this->assignment->get_context());
+        $this->hasgrade = $this->assignment->can_grade();
+
         foreach ($assignment->get_feedback_plugins() as $plugin) {
             if ($plugin->is_visible() && $plugin->is_enabled()) {
                 foreach ($plugin->get_grading_batch_operations() as $action => $description) {
@@ -94,7 +101,7 @@ class assign_grading_table extends table_sql implements renderable {
             }
         }
         $this->perpage = $perpage;
-        $this->quickgrading = $quickgrading;
+        $this->quickgrading = $quickgrading && $this->hasgrade;
         $this->output = $PAGE->get_renderer('mod_assign');
 
         $urlparams = array('action'=>'grading', 'id'=>$assignment->get_course_module()->id);
@@ -225,7 +232,7 @@ class assign_grading_table extends table_sql implements renderable {
         $headers = array();
 
         // Select.
-        if (!$this->is_downloading()) {
+        if (!$this->is_downloading() && $this->hasgrade) {
             $columns[] = 'select';
             $headers[] = get_string('select') .
                     '<div class="selectall"><label class="accesshide" for="selectall">' . get_string('selectall') . '</label>
@@ -302,7 +309,7 @@ class assign_grading_table extends table_sql implements renderable {
             $columns[] = 'gradecanbechanged';
             $headers[] = get_string('gradecanbechanged', 'assign');
         }
-        if (!$this->is_downloading()) {
+        if (!$this->is_downloading() && $this->hasgrade) {
             // We have to call this column userid so we can use userid as a default sortable column.
             $columns[] = 'userid';
             $headers[] = get_string('edit');
@@ -370,8 +377,6 @@ class assign_grading_table extends table_sql implements renderable {
                                               'assign',
                                               $this->assignment->get_instance()->id,
                                               $users);
-        $this->hasgrantextension = has_capability('mod/assign:grantextension',
-                                                  $this->assignment->get_context());
 
         if (!empty($CFG->enableoutcomes) && !empty($this->gradinginfo->outcomes)) {
             $columns[] = 'outcomes';
@@ -809,7 +814,7 @@ class assign_grading_table extends table_sql implements renderable {
         $grade = '';
         $gradingdisabled = $this->assignment->grading_disabled($row->id);
 
-        if (!$this->is_downloading()) {
+        if (!$this->is_downloading() && $this->hasgrade) {
             $name = fullname($row);
             if ($this->assignment->is_blind_marking()) {
                 $name = get_string('hiddenuser', 'assign') .
@@ -1288,7 +1293,7 @@ class assign_grading_table extends table_sql implements renderable {
      * @return string HTML fragment.
      */
     protected function show_hide_link($column, $index) {
-        if ($index > 0) {
+        if ($index > 0 || !$this->hasgrade) {
             return parent::show_hide_link($column, $index);
         }
         return '';
index e54996a..916df63 100644 (file)
@@ -49,6 +49,7 @@ $string['assign:managegrades'] = 'Review and release grades';
 $string['assign:releasegrades'] = 'Release grades';
 $string['assign:revealidentities'] = 'Reveal student identities';
 $string['assign:reviewgrades'] = 'Review grades';
+$string['assign:viewgrades'] = 'View grades';
 $string['assign:submit'] = 'Submit assignment';
 $string['assign:view'] = 'View assignment';
 $string['assignfeedback'] = 'Feedback plugin';
index 67b2ffd..42dff0a 100644 (file)
@@ -223,7 +223,7 @@ function assign_extend_settings_navigation(settings_navigation $settings, naviga
     }
 
     // Link to download all submissions.
-    if (has_capability('mod/assign:grade', $context)) {
+    if (has_any_capability(array('mod/assign:grade', 'mod/assign:viewgrades'), $context)) {
         $link = new moodle_url('/mod/assign/view.php', array('id' => $cm->id, 'action'=>'grading'));
         $node = $navref->add(get_string('viewgrading', 'assign'), $link, navigation_node::TYPE_SETTING);
 
@@ -912,6 +912,19 @@ function assign_grade_item_update($assign, $grades=null) {
 
     $params = array('itemname'=>$assign->name, 'idnumber'=>$assign->cmidnumber);
 
+    // Check if feedback plugin for gradebook is enabled, if yes then
+    // gradetype = GRADE_TYPE_TEXT else GRADE_TYPE_NONE.
+    $gradefeedbackenabled = false;
+
+    if (isset($assign->gradefeedbackenabled)) {
+        $gradefeedbackenabled = $assign->gradefeedbackenabled;
+    } else if ($assign->grade == 0) { // Grade feedback is needed only when grade == 0.
+        $mod = get_coursemodule_from_instance('assign', $assign->id, $assign->courseid);
+        $cm = context_module::instance($mod->id);
+        $assignment = new assign($cm, null, null);
+        $gradefeedbackenabled = $assignment->is_gradebook_feedback_enabled();
+    }
+
     if ($assign->grade > 0) {
         $params['gradetype'] = GRADE_TYPE_VALUE;
         $params['grademax']  = $assign->grade;
@@ -921,9 +934,12 @@ function assign_grade_item_update($assign, $grades=null) {
         $params['gradetype'] = GRADE_TYPE_SCALE;
         $params['scaleid']   = -$assign->grade;
 
-    } else {
-        // Allow text comments only.
+    } else if ($gradefeedbackenabled) {
+        // $assign->grade == 0 and feedback enabled.
         $params['gradetype'] = GRADE_TYPE_TEXT;
+    } else {
+        // $assign->grade == 0 and no feedback enabled.
+        $params['gradetype'] = GRADE_TYPE_NONE;
     }
 
     if ($grades  === 'reset') {
index c3667df..2d5acfd 100644 (file)
@@ -788,6 +788,10 @@ class assign {
         require_once($CFG->dirroot.'/mod/assign/lib.php');
         $assign = clone $this->get_instance();
         $assign->cmidnumber = $coursemoduleid;
+
+        // Set assign gradebook feedback plugin status (enabled and visible).
+        $assign->gradefeedbackenabled = $this->is_gradebook_feedback_enabled();
+
         $param = null;
         if ($reset) {
             $param = 'reset';
@@ -827,30 +831,37 @@ class assign {
             $event = new stdClass();
 
             $params = array('modulename'=>'assign', 'instance'=>$instance->id);
-            $event->id = $DB->get_field('event',
-                                        'id',
-                                        $params);
+            $event->id = $DB->get_field('event', 'id', $params);
+            $event->name = $instance->name;
+            $event->timestart = $instance->duedate;
+
+            // Convert the links to pluginfile. It is a bit hacky but at this stage the files
+            // might not have been saved in the module area yet.
+            $intro = $instance->intro;
+            if ($draftid = file_get_submitted_draft_itemid('introeditor')) {
+                $intro = file_rewrite_urls_to_pluginfile($intro, $draftid);
+            }
+
+            // We need to remove the links to files as the calendar is not ready
+            // to support module events with file areas.
+            $intro = strip_pluginfile_content($intro);
+            $event->description = array(
+                'text' => $intro,
+                'format' => $instance->introformat
+            );
 
             if ($event->id) {
-                $event->name        = $instance->name;
-                $event->description = format_module_intro('assign', $instance, $coursemoduleid);
-                $event->timestart   = $instance->duedate;
-
                 $calendarevent = calendar_event::load($event->id);
                 $calendarevent->update($event);
             } else {
-                $event = new stdClass();
-                $event->name        = $instance->name;
-                $event->description = format_module_intro('assign', $instance, $coursemoduleid);
+                unset($event->id);
                 $event->courseid    = $instance->course;
                 $event->groupid     = 0;
                 $event->userid      = 0;
                 $event->modulename  = 'assign';
                 $event->instance    = $instance->id;
                 $event->eventtype   = 'due';
-                $event->timestart   = $instance->duedate;
                 $event->timeduration = 0;
-
                 calendar_event::create($event);
             }
         } else {
@@ -2130,9 +2141,7 @@ class assign {
             $item = $this->get_submission($submissionid);
 
             // Check permissions.
-            if ($item->userid != $USER->id) {
-                require_capability('mod/assign:grade', $this->context);
-            }
+            $this->require_view_submission($item->userid);
             $o .= $this->get_renderer()->render(new assign_header($this->get_instance(),
                                                               $this->get_context(),
                                                               $this->show_intro(),
@@ -2154,9 +2163,7 @@ class assign {
             }
             $item = $this->get_grade($gradeid);
             // Check permissions.
-            if ($item->userid != $USER->id) {
-                require_capability('mod/assign:grade', $this->context);
-            }
+            $this->require_view_submission($item->userid);
             $o .= $this->get_renderer()->render(new assign_header($this->get_instance(),
                                                               $this->get_context(),
                                                               $this->show_intro(),
@@ -2318,6 +2325,44 @@ class assign {
         return $this->get_renderer()->render_footer();
     }
 
+    /**
+     * Throw an error if the permissions to view this users submission are missing.
+     *
+     * @throws required_capability_exception
+     * @return none
+     */
+    public function require_view_submission($userid) {
+        if (!$this->can_view_submission($userid)) {
+            throw new required_capability_exception($this->context, 'mod/assign:viewgrades', 'nopermission', '');
+        }
+    }
+
+    /**
+     * Throw an error if the permissions to view grades in this assignment are missing.
+     *
+     * @throws required_capability_exception
+     * @return none
+     */
+    public function require_view_grades() {
+        if (!$this->can_view_grades()) {
+            throw new required_capability_exception($this->context, 'mod/assign:viewgrades', 'nopermission', '');
+        }
+    }
+
+    /**
+     * Does this user have view grade or grade permission for this assignment?
+     *
+     * @return bool
+     */
+    public function can_view_grades() {
+        // Permissions check.
+        if (!has_any_capability(array('mod/assign:viewgrades', 'mod/assign:grade'), $this->context)) {
+            return false;
+        }
+
+        return true;
+    }
+
     /**
      * Does this user have grade permission for this assignment?
      *
@@ -2343,7 +2388,7 @@ class assign {
         // More efficient to load this here.
         require_once($CFG->libdir.'/filelib.php');
 
-        require_capability('mod/assign:grade', $this->context);
+        $this->require_view_grades();
 
         // Load all users with submit.
         $students = get_enrolled_users($this->context, "mod/assign:submit", null, 'u.*', null, null, null,
@@ -2968,7 +3013,7 @@ class assign {
         $markerfilter = get_user_preferences('assign_markerfilter', '');
         $workflowfilter = get_user_preferences('assign_workflowfilter', '');
         $controller = $gradingmanager->get_active_controller();
-        $showquickgrading = empty($controller);
+        $showquickgrading = empty($controller) && $this->can_grade();
         $quickgrading = get_user_preferences('assign_quickgrading', false);
         $showonlyactiveenrolopt = has_capability('moodle/course:viewsuspendedusers', $this->context);
 
@@ -3073,7 +3118,7 @@ class assign {
 
         $currentgroup = groups_get_activity_group($this->get_course_module(), true);
         $users = array_keys($this->list_participants($currentgroup, true));
-        if (count($users) != 0) {
+        if (count($users) != 0 && $this->can_grade()) {
             // If no enrolled user in a course then don't display the batch operations feature.
             $assignform = new assign_form('gradingbatchoperationsform', $gradingbatchoperationsform);
             $o .= $this->get_renderer()->render($assignform);
@@ -3095,7 +3140,7 @@ class assign {
 
         $o = '';
         // Need submit permission to submit an assignment.
-        require_capability('mod/assign:grade', $this->context);
+        $this->require_view_grades();
         require_once($CFG->dirroot . '/mod/assign/gradeform.php');
 
         // Only load this if it is.
@@ -3247,7 +3292,7 @@ class assign {
         if (!$this->is_active_user($userid) && !has_capability('moodle/course:viewsuspendedusers', $this->context)) {
             return false;
         }
-        if (has_capability('mod/assign:grade', $this->context)) {
+        if (has_any_capability(array('mod/assign:viewgrades', 'mod/assign:grade'), $this->context)) {
             return true;
         }
         if (!is_enrolled($this->get_course_context(), $userid)) {
@@ -3866,7 +3911,7 @@ class assign {
                                                       $this->show_intro(),
                                                       $this->get_course_module()->id));
 
-        if ($this->can_grade()) {
+        if ($this->can_view_grades()) {
             $draft = ASSIGN_SUBMISSION_STATUS_DRAFT;
             $submitted = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
             if ($instance->teamsubmission) {
@@ -3999,7 +4044,8 @@ class assign {
         }
         $assign = clone $this->get_instance();
         $assign->cmidnumber = $this->get_course_module()->idnumber;
-
+        // Set assign gradebook feedback plugin status (enabled and visible).
+        $assign->gradefeedbackenabled = $this->is_gradebook_feedback_enabled();
         return assign_grade_item_update($assign, $gradebookgrade);
     }
 
@@ -5958,6 +6004,8 @@ class assign {
                     // Update Gradebook.
                     $assign = clone $this->get_instance();
                     $assign->cmidnumber = $this->get_course_module()->idnumber;
+                    // Set assign gradebook feedback plugin status.
+                    $assign->gradefeedbackenabled = $this->is_gradebook_feedback_enabled();
                     assign_update_grades($assign, $userid);
                 }
 
@@ -6779,6 +6827,28 @@ class assign {
         }
         return !in_array($userid, $this->susers);
     }
+
+    /**
+     * Returns true if gradebook feedback plugin is enabled
+     *
+     * @return bool true if gradebook feedback plugin is enabled and visible else false.
+     */
+    public function is_gradebook_feedback_enabled() {
+        // Get default grade book feedback plugin.
+        $adminconfig = $this->get_admin_config();
+        $gradebookplugin = $adminconfig->feedback_plugin_for_gradebook;
+        $gradebookplugin = str_replace('assignfeedback_', '', $gradebookplugin);
+
+        // Check if default gradebook feedback is visible and enabled.
+        $gradebookfeedbackplugin = $this->get_feedback_plugin_by_type($gradebookplugin);
+
+        if ($gradebookfeedbackplugin->is_visible() && $gradebookfeedbackplugin->is_enabled()) {
+            return true;
+        }
+
+        // Gradebook feedback plugin is either not visible/enabled.
+        return false;
+    }
 }
 
 /**
diff --git a/mod/assign/submission/comments/classes/event/comment_created.php b/mod/assign/submission/comments/classes/event/comment_created.php
new file mode 100644 (file)
index 0000000..0339217
--- /dev/null
@@ -0,0 +1,53 @@
+<?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/>.
+
+/**
+ * assignsubmission_comments comment created event.
+ *
+ * @package    assignsubmission_comments
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace assignsubmission_comments\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * assignsubmission_comments comment created event.
+ *
+ * @package    assignsubmission_comments
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class comment_created extends \core\event\comment_created {
+    /**
+     * Get URL related to the action.
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return 'User with id ' . $this->userid . ' added comment for assignment submission with id ' . $this->other['itemid'];
+    }
+}
diff --git a/mod/assign/submission/comments/classes/event/comment_deleted.php b/mod/assign/submission/comments/classes/event/comment_deleted.php
new file mode 100644 (file)
index 0000000..2b11fa3
--- /dev/null
@@ -0,0 +1,53 @@
+<?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/>.
+
+/**
+ * assignsubmission_comments comment deleted event.
+ *
+ * @package    assignsubmission_comments
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace assignsubmission_comments\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * assignsubmission_comments comment deleted event.
+ *
+ * @package    assignsubmission_comments
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class comment_deleted extends \core\event\comment_deleted {
+    /**
+     * Get URL related to the action.
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return 'User with id ' . $this->userid . ' deleted comment for assignment submission with id ' . $this->other['itemid'];
+    }
+}
index 6bdb6ed..259a99c 100644 (file)
@@ -48,21 +48,14 @@ function assignsubmission_comments_comment_validate(stdClass $options) {
     if ($assignment->get_instance()->id != $submission->assignment) {
         throw new comment_exception('invalidcontext');
     }
-    if (!has_capability('mod/assign:grade', $context)) {
-        if (!has_capability('mod/assign:submit', $context)) {
-            throw new comment_exception('nopermissiontocomment');
-        } else if ($assignment->get_instance()->teamsubmission) {
-            $group = $assignment->get_submission_group($USER->id);
-            $groupid = 0;
-            if ($group) {
-                $groupid = $group->id;
-            }
-            if ($groupid != $submission->groupid) {
-                throw new comment_exception('nopermissiontocomment');
-            }
-        } else if ($submission->userid != $USER->id) {
-            throw new comment_exception('nopermissiontocomment');
-        }
+    $canview = false;
+    if ($submission->userid) {
+        $canview = $assignment->can_view_submission($submission->userid);
+    } else {
+        $canview = $assignment->can_view_group_submission($submission->groupid);
+    }
+    if (!$canview) {
+        throw new comment_exception('nopermissiontocomment');
     }
 
     return true;
diff --git a/mod/assign/submission/comments/tests/events_test.php b/mod/assign/submission/comments/tests/events_test.php
new file mode 100644 (file)
index 0000000..0357606
--- /dev/null
@@ -0,0 +1,116 @@
+<?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/>.
+
+/**
+ * Events tests.
+ *
+ * @package    assignsubmission_comments
+ * @category   test
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/mod/assign/lib.php');
+require_once($CFG->dirroot . '/mod/assign/locallib.php');
+require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+
+/**
+ * Events tests class.
+ *
+ * @package    assignsubmission_comments
+ * @category   test
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class assignsubmission_comments_events_testcase extends mod_assign_base_testcase {
+
+    /**
+     * Test comment_created event.
+     */
+    public function test_comment_created() {
+        global $CFG;
+        require_once($CFG->dirroot . '/comment/lib.php');
+
+        $this->setUser($this->editingteachers[0]);
+        $assign = $this->create_instance();
+        $submission = $assign->get_user_submission($this->students[0]->id, true);
+
+        $context = $assign->get_context();
+        $options = new stdClass();
+        $options->area = 'submission_comments';
+        $options->course = $assign->get_course();
+        $options->context = $context;
+        $options->itemid = $submission->id;
+        $options->component = 'assignsubmission_comments';
+        $options->showcount = true;
+        $options->displaycancel = true;
+
+        $comment = new comment($options);
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $comment->add('New comment');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\assignsubmission_comments\event\comment_created', $event);
+        $this->assertEquals($context, $event->get_context());
+        $url = new moodle_url('/mod/assign/view.php', array('id' => $submission->id));
+        $this->assertEquals($url, $event->get_url());
+    }
+
+    /**
+     * Test comment_deleted event.
+     */
+    public function test_comment_deleted() {
+        global $CFG;
+        require_once($CFG->dirroot . '/comment/lib.php');
+
+        $this->setUser($this->editingteachers[0]);
+        $assign = $this->create_instance();
+        $submission = $assign->get_user_submission($this->students[0]->id, true);
+
+        $context = $assign->get_context();
+        $options = new stdClass();
+        $options->area    = 'submission_comments';
+        $options->course    = $assign->get_course();
+        $options->context = $context;
+        $options->itemid  = $submission->id;
+        $options->component = 'assignsubmission_comments';
+        $options->showcount = true;
+        $options->displaycancel = true;
+        $comment = new comment($options);
+        $newcomment = $comment->add('New comment 1');
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $comment->delete($newcomment->id);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\assignsubmission_comments\event\comment_deleted', $event);
+        $this->assertEquals($context, $event->get_context());
+        $url = new moodle_url('/mod/assign/view.php', array('id' => $submission->id));
+        $this->assertEquals($url, $event->get_url());
+    }
+}
index 0f2ccc7..b32eb00 100644 (file)
@@ -29,6 +29,13 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * assignsubmission_file assessable uploaded event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type array pathnamehashes uploaded files path name hash.
+ *      @type string content empty string.
+ * }
+ *
  * @package    assignsubmission_file
  * @copyright  2013 Frédéric Massart