Merge branch '44185-27' of git://github.com/samhemelryk/moodle
authorDan Poltawski <dan@moodle.com>
Tue, 25 Feb 2014 03:22:24 +0000 (11:22 +0800)
committerDan Poltawski <dan@moodle.com>
Tue, 25 Feb 2014 03:22:24 +0000 (11:22 +0800)
304 files changed:
admin/handlevirus.php [deleted file]
admin/renderer.php
admin/settings/users.php
admin/tool/behat/tests/behat/data_generators.feature
admin/tool/spamcleaner/index.php
auth/cas/auth.php
auth/ldap/auth.php
cache/stores/memcache/lib.php
cache/stores/memcached/lib.php
cache/stores/mongodb/lib.php
composer.json
files/renderer.php
lang/en/moodle.php
lang/en/question.php
lang/en/repository.php
lib/adminlib.php
lib/ajax/ajaxlib.php
lib/behat/behat_base.php
lib/cronlib.php
lib/db/access.php
lib/db/services.php
lib/deprecatedlib.php
lib/dtl/database_exporter.php
lib/dtl/database_importer.php
lib/dtl/file_xml_database_exporter.php
lib/dtl/string_xml_database_exporter.php
lib/filestorage/file_exceptions.php
lib/formslib.php
lib/outputlib.php
lib/outputrequirementslib.php
lib/pagelib.php
lib/statslib.php
lib/testing/generator/data_generator.php
lib/tests/behat/behat_data_generators.php
lib/tests/behat/behat_forms.php
lib/tests/behat/behat_general.php
lib/tests/behat/behat_hooks.php
lib/uploadlib.php
lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-debug.js
lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-min.js
lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.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/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose-debug.js [new file with mode: 0644]
lib/yui/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose-min.js [new file with mode: 0644]
lib/yui/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose.js [new file with mode: 0644]
lib/yui/src/chooserdialogue/js/chooserdialogue.js
lib/yui/src/notification/js/dialogue.js
lib/yui/src/notification/meta/notification.json
lib/yui/src/tooltip/js/tooltip.js
lib/yui/src/widget-focusafterclose/build.json [new file with mode: 0644]
lib/yui/src/widget-focusafterclose/js/focusafter.js [new file with mode: 0644]
lib/yui/src/widget-focusafterclose/meta/notification.json [new file with mode: 0644]
mod/assign/feedback/editpdf/fpdi/fpdf_tpl.php
mod/forum/search.php
mod/imscp/backup/moodle1/lib.php
mod/imscp/backup/moodle2/backup_imscp_stepslib.php
mod/imscp/backup/moodle2/restore_imscp_activity_task.class.php
mod/imscp/backup/moodle2/restore_imscp_stepslib.php
mod/imscp/classes/event/course_module_instance_list_viewed.php [new file with mode: 0644]
mod/imscp/classes/event/course_module_viewed.php [new file with mode: 0644]
mod/imscp/db/install.php
mod/imscp/db/upgrade.php
mod/imscp/index.php
mod/imscp/lang/en/imscp.php
mod/imscp/lib.php
mod/imscp/locallib.php
mod/imscp/mod_form.php
mod/imscp/settings.php
mod/imscp/version.php
mod/imscp/view.php
mod/label/backup/moodle1/lib.php
mod/label/backup/moodle2/backup_label_stepslib.php
mod/label/backup/moodle2/restore_label_activity_task.class.php
mod/label/backup/moodle2/restore_label_stepslib.php
mod/label/db/upgrade.php
mod/label/index.php
mod/label/lang/en/label.php
mod/label/lib.php
mod/label/mod_form.php
mod/label/version.php
mod/label/view.php
mod/lesson/backup/moodle1/lib.php
mod/lesson/backup/moodle2/backup_lesson_stepslib.php
mod/lesson/backup/moodle2/restore_lesson_activity_task.class.php
mod/lesson/backup/moodle2/restore_lesson_stepslib.php
mod/lesson/continue.php
mod/lesson/db/messages.php
mod/lesson/db/upgrade.php
mod/lesson/edit.php
mod/lesson/editpage.php
mod/lesson/editpage_form.php
mod/lesson/essay.php
mod/lesson/essay_form.php
mod/lesson/format.php
mod/lesson/highscores.php
mod/lesson/import.php
mod/lesson/import_form.php
mod/lesson/index.php
mod/lesson/lang/en/lesson.php
mod/lesson/lesson.php
mod/lesson/lib.php
mod/lesson/locallib.php
mod/lesson/mediafile.php
mod/lesson/mod_form.php
mod/lesson/pagetypes/branchtable.php
mod/lesson/pagetypes/cluster.php
mod/lesson/pagetypes/endofbranch.php
mod/lesson/pagetypes/endofcluster.php
mod/lesson/pagetypes/essay.php
mod/lesson/pagetypes/matching.php
mod/lesson/pagetypes/multichoice.php
mod/lesson/pagetypes/numerical.php
mod/lesson/pagetypes/shortanswer.php
mod/lesson/pagetypes/truefalse.php
mod/lesson/reformat.php
mod/lesson/renderer.php
mod/lesson/report.php
mod/lesson/settings.php
mod/lesson/tabs.php
mod/lesson/version.php
mod/lesson/view.php
mod/lesson/view_form.php
mod/lti/TrivialStore.php
mod/lti/backup/moodle1/lib.php
mod/lti/backup/moodle2/backup_lti_stepslib.php
mod/lti/backup/moodle2/restore_lti_activity_task.class.php
mod/lti/backup/moodle2/restore_lti_stepslib.php
mod/lti/db/upgrade.php
mod/lti/edit_form.php
mod/lti/grade.php
mod/lti/index.php
mod/lti/instructor_edit_tool_type.php
mod/lti/lang/en/lti.php
mod/lti/launch.php
mod/lti/lib.php
mod/lti/localadminlib.php
mod/lti/locallib.php
mod/lti/mod_form.php
mod/lti/request_tool.php
mod/lti/return.php
mod/lti/service.php
mod/lti/servicelib.php
mod/lti/settings.php
mod/lti/typessettings.php
mod/lti/version.php
mod/lti/view.php
mod/page/backup/moodle1/lib.php
mod/page/backup/moodle2/backup_page_stepslib.php
mod/page/backup/moodle2/restore_page_activity_task.class.php
mod/page/backup/moodle2/restore_page_stepslib.php
mod/page/db/install.php
mod/page/db/upgrade.php
mod/page/index.php
mod/page/lang/en/page.php
mod/page/lib.php
mod/page/locallib.php
mod/page/mod_form.php
mod/page/settings.php
mod/page/version.php
mod/page/view.php
mod/quiz/lib.php
mod/quiz/report/attemptsreport_table.php
mod/quiz/report/responses/first_or_all_responses_table.php [new file with mode: 0644]
mod/quiz/report/responses/last_responses_table.php [moved from mod/quiz/report/responses/responses_table.php with 88% similarity]
mod/quiz/report/responses/report.php
mod/quiz/report/responses/responses_form.php
mod/quiz/report/responses/responses_options.php
mod/quiz/report/responses/tests/fixtures/questions00.csv [new file with mode: 0644]
mod/quiz/report/responses/tests/fixtures/quizzes.csv [new file with mode: 0644]
mod/quiz/report/responses/tests/fixtures/responses00.csv [new file with mode: 0644]
mod/quiz/report/responses/tests/fixtures/steps00.csv [new file with mode: 0644]
mod/quiz/report/responses/tests/responses_from_steps_walkthrough_test.php [new file with mode: 0644]
mod/quiz/styles.css
mod/quiz/tests/attempt_walkthrough_from_csv_test.php
mod/quiz/tests/behat/add_quiz.feature [new file with mode: 0644]
mod/quiz/tests/behat/behat_mod_quiz.php [new file with mode: 0644]
mod/scorm/mod_form.php
mod/survey/backup/moodle1/lib.php
mod/survey/backup/moodle2/backup_survey_stepslib.php
mod/survey/backup/moodle2/restore_survey_activity_task.class.php
mod/survey/backup/moodle2/restore_survey_stepslib.php
mod/survey/download.php
mod/survey/lang/en/survey.php
mod/survey/lib.php
mod/survey/report.php
mod/survey/save.php
mod/survey/version.php
mod/survey/view.php
mod/wiki/admin.php
mod/wiki/backup/moodle1/lib.php
mod/wiki/backup/moodle2/backup_wiki_settingslib.php
mod/wiki/backup/moodle2/backup_wiki_stepslib.php
mod/wiki/backup/moodle2/restore_wiki_activity_task.class.php
mod/wiki/backup/moodle2/restore_wiki_stepslib.php
mod/wiki/comments.php
mod/wiki/create_form.php
mod/wiki/db/upgrade.php
mod/wiki/diff.php
mod/wiki/edit.php
mod/wiki/edit_form.php
mod/wiki/editcomments.php
mod/wiki/editors/html.php
mod/wiki/editors/wiki_editor.php
mod/wiki/editors/wikieditor.php
mod/wiki/editors/wikifiletable.php
mod/wiki/files.php
mod/wiki/filesedit.php
mod/wiki/filesedit_form.php
mod/wiki/history.php
mod/wiki/index.php
mod/wiki/instancecomments.php
mod/wiki/lang/en/wiki.php
mod/wiki/lib.php
mod/wiki/locallib.php
mod/wiki/lock.php
mod/wiki/map.php
mod/wiki/mod_form.php
mod/wiki/overridelocks.php
mod/wiki/pagelib.php
mod/wiki/parser/markups/creole.php
mod/wiki/parser/markups/html.php
mod/wiki/parser/markups/nwiki.php
mod/wiki/parser/markups/wikimarkup.php
mod/wiki/parser/parser.php
mod/wiki/parser/utils.php
mod/wiki/prettyview.php
mod/wiki/renderer.php
mod/wiki/restoreversion.php
mod/wiki/search.php
mod/wiki/version.php
mod/wiki/view.php
mod/wiki/viewversion.php
mod/workshop/aggregate.php
mod/workshop/allocation.php
mod/workshop/allocation/lib.php
mod/workshop/assessment.php
mod/workshop/backup/moodle1/lib.php
mod/workshop/backup/moodle2/restore_workshop_activity_task.class.php
mod/workshop/backup/moodle2/restore_workshop_stepslib.php
mod/workshop/db/subplugins.php
mod/workshop/db/uninstall.php
mod/workshop/editform.php
mod/workshop/editformpreview.php
mod/workshop/eval/lib.php
mod/workshop/exassessment.php
mod/workshop/excompare.php
mod/workshop/exsubmission.php
mod/workshop/feedbackauthor_form.php
mod/workshop/feedbackreviewer_form.php
mod/workshop/form/assessment_form.php
mod/workshop/form/edit_form.php
mod/workshop/form/lib.php
mod/workshop/index.php
mod/workshop/lang/en/workshop.php
mod/workshop/lib.php
mod/workshop/locallib.php
mod/workshop/mod_form.php
mod/workshop/renderer.php
mod/workshop/settings.php
mod/workshop/submission.php
mod/workshop/submission_form.php
mod/workshop/switchphase.php
mod/workshop/toolbox.php
mod/workshop/view.php
question/behaviour/adaptive/behaviour.php
question/behaviour/adaptive/behaviourtype.php
question/behaviour/behaviourbase.php
question/behaviour/behaviourtypebase.php
question/behaviour/interactive/behaviour.php
question/behaviour/interactive/behaviourtype.php
question/behaviour/upgrade.txt
question/engine/datalib.php
question/engine/questionattempt.php
question/engine/questionusage.php
question/type/calculatedsimple/edit_calculatedsimple_form.php
repository/flickr_public/lang/en/repository_flickr_public.php
repository/flickr_public/lib.php
theme/base/style/admin.css
theme/base/style/filemanager.css
theme/bootstrapbase/config.php
theme/bootstrapbase/less/README
theme/bootstrapbase/less/moodle.less
theme/bootstrapbase/less/moodle/admin.less
theme/bootstrapbase/less/moodle/filemanager.less
theme/bootstrapbase/less/moodle/responsive.less
theme/bootstrapbase/style/moodle.css
theme/bootstrapbase/version.php
theme/canvas/style/admin.css
theme/clean/layout/columns1.php
theme/clean/layout/columns2.php
theme/clean/layout/columns3.php
theme/formal_white/style/core.css
theme/standard/style/admin.css
theme/yui_combo.php
user/lib.php
user/profile.php
user/tests/externallib_test.php
user/view.php
version.php

diff --git a/admin/handlevirus.php b/admin/handlevirus.php
deleted file mode 100644 (file)
index 36cc0e3..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-<?php
-/** This expects the output from a command like
- * clamscan -r --infected --no-summary <files> 2>&1 | php -d error_log=/path/to/log thisfile.php
- * also it's important that the output of clamscan prints the FULL PATH to each infected file, so use absolute paths for area to scan
- * also it should be run as root, or whatever the webserver runs as so that it has the right permissions in the quarantine dir etc.
- * php -d error_log=/path/to/log thisfile.php will override the default error log for php cli, which is stderr, so if you want this script to just print stuff out, use php thisfile.php instead.
- */
-
-die('TODO: MDL-19380');
-
-$fd = fopen('php://stdin','r');
-if (!$fd) {
-    exit();
-}
-
-require_once(dirname(dirname(__FILE__)).'/config.php');
-require_once($CFG->libdir.'/eventslib.php');
-require_once($CFG->dirroot.'/lib/uploadlib.php'); // contains virus handling stuff.
-
-$site = get_site();
-
-while(!feof($fd)) {
-    $entry = fgets($fd);
-    if (strlen(trim($entry)) == 0) {
-        continue;
-    }
-    if (!$file = validate_line($entry)) {
-        continue;
-    }
-    $bits = explode('/',$file);
-    $a->filename = $bits[count($bits)-1];
-
-    if (!$log = $DB->get_record("log", array("module"=>"upload", "info"=>$file, "action"=>"upload"))) {
-        $a->action = clam_handle_infected_file($file,0,false);
-        clam_replace_infected_file($file);
-        notify_admins_unknown($file,$a);
-        continue;
-    }
-    $action = clam_handle_infected_file($file,$log->userid,true);
-    clam_replace_infected_file($file);
-
-    $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
-    $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)";
-    $sql = "SELECT c.id, c.fullname $ctxselect FROM {course} c $ctxjoin WHERE c.id = :courseid";
-    $course = $DB->get_record_sql($sql, array('courseid' => $log->course, 'contextlevel' => CONTEXT_COURSE));
-    context_helper::preload_from_record($course);
-
-    $user = $DB->get_record("user", array("id"=>$log->userid));
-    $subject = get_string('virusfoundsubject','moodle',format_string($site->fullname));
-    $a->date = userdate($log->time);
-
-    $a->action = $action;
-    $a->course = format_string($course->fullname, true, array('context' => context_course::instance($course->id)));
-    $a->user = fullname($user);
-
-    notify_user($user,$subject,$a);
-    notify_admins($user,$subject,$a);
-}
-fclose($fd);
-
-
-function notify_user($user,$subject,$a) {
-
-    if (!$user) {
-        return false;
-    }
-    $body = get_string('virusfoundlater','moodle',$a);
-
-    $eventdata = new stdClass();
-    $eventdata->modulename        = 'moodle';
-    $eventdata->userfrom          = get_admin();
-    $eventdata->userto            = $user;
-    $eventdata->subject           = $subject;
-    $eventdata->fullmessage       = $body;
-    $eventdata->fullmessageformat = FORMAT_PLAIN;
-    $eventdata->fullmessagehtml   = '';
-    $eventdata->smallmessage      = '';
-    message_send($eventdata);
-}
-
-
-function notify_admins($user,$subject,$a) {
-
-    $admins = get_admins();
-
-    $body = get_string('virusfoundlateradmin','moodle',$a);
-    foreach ($admins as $admin) {
-        $eventdata = new stdClass();
-        $eventdata->modulename        = 'moodle';
-        $eventdata->userfrom          = get_admin();
-        $eventdata->userto            = $admin;
-        $eventdata->subject           = $subject;
-        $eventdata->fullmessage       = $body;
-        $eventdata->fullmessageformat = FORMAT_PLAIN;
-        $eventdata->fullmessagehtml   = '';
-        $eventdata->smallmessage      = '';
-        message_send($eventdata);
-    }
-}
-
-function notify_admins_unknown($file,$a) {
-
-    global $site;
-
-    $admins = get_admins();
-    $subject = get_string('virusfoundsubject','moodle',format_string($site->fullname));
-    $body = get_string('virusfoundlateradminnolog','moodle',$a);
-    foreach ($admins as $admin) {
-        $eventdata = new stdClass();
-        $eventdata->modulename        = 'moodle';
-        $eventdata->userfrom          = get_admin();
-        $eventdata->userto            = $admin;
-        $eventdata->subject           = $subject;
-        $eventdata->fullmessage       = $body;
-        $eventdata->fullmessageformat = FORMAT_PLAIN;
-        $eventdata->fullmessagehtml   = '';
-        $eventdata->smallmessage      = '';
-        message_send($eventdata);
-    }
-}
-
-function validate_line($line) {
-    global $CFG;
-    if (strpos($line,"FOUND") === false) {
-        return false;
-    }
-    $index = strpos($line,":");
-    $file = substr($line,0,$index);
-    if (!(strpos($file,$CFG->dataroot) === false)) {
-        if (!file_exists($file)) {
-            return false;
-        }
-    }
-    else {
-        if ($file{0} == "/") {
-            $file = $CFG->dataroot.$file;
-        }
-        else {
-            $file = $CFG->dataroot."/".$file;
-        }
-        if (!file_exists($file)) {
-            return false;
-        }
-    }
-    // clean up
-    $file = preg_replace('/\.\//','/',$file);
-    $file = preg_replace('/\/\//','/',$file);
-    return $file;
-}
-
-
index 3ba44bb..1588436 100644 (file)
@@ -610,10 +610,10 @@ class core_admin_renderer extends plugin_renderer_base {
         }
 
         $maturitylevel = get_string('maturity' . $maturity, 'admin');
-        return $this->box(
+        return $this->warning(
                     $this->container(get_string('maturitycorewarning', 'admin', $maturitylevel)) .
                     $this->container($this->doc_link('admin/versions', get_string('morehelp'))),
-                'generalbox maturitywarning');
+                'error');
     }
 
     /*
@@ -628,10 +628,8 @@ class core_admin_renderer extends plugin_renderer_base {
             return '';
         }
 
-        return $this->box(
-            $this->container(get_string('testsiteupgradewarning', 'admin', $testsite)),
-            'generalbox testsitewarning'
-        );
+        $warning = (get_string('testsiteupgradewarning', 'admin', $testsite));
+        return $this->warning($warning, 'error');
     }
 
     /**
@@ -663,11 +661,16 @@ class core_admin_renderer extends plugin_renderer_base {
             return ''; // No worries.
         }
 
+        $level = 'warning';
+
+        if ($maturity == MATURITY_ALPHA) {
+            $level = 'error';
+        }
+
         $maturitylevel = get_string('maturity' . $maturity, 'admin');
-        return $this->box(
-                    get_string('maturitycoreinfo', 'admin', $maturitylevel) . ' ' .
-                    $this->doc_link('admin/versions', get_string('morehelp')),
-                'generalbox adminwarning maturityinfo maturity'.$maturity);
+        $warningtext = get_string('maturitycoreinfo', 'admin', $maturitylevel);
+        $warningtext .= ' ' . $this->doc_link('admin/versions', get_string('morehelp'));
+        return $this->warning($warningtext, $level);
     }
 
     /**
@@ -682,7 +685,7 @@ class core_admin_renderer extends plugin_renderer_base {
      */
     protected function available_updates($updates, $fetch) {
 
-        $updateinfo = $this->box_start('generalbox adminwarning availableupdatesinfo');
+        $updateinfo = '';
         $someupdateavailable = false;
         if (is_array($updates)) {
             if (is_array($updates['core'])) {
@@ -719,9 +722,7 @@ class core_admin_renderer extends plugin_renderer_base {
         }
         $updateinfo .= $this->container_end();
 
-        $updateinfo .= $this->box_end();
-
-        return $updateinfo;
+        return $this->warning($updateinfo);
     }
 
     /**
index 5a50bce..2231bab 100644 (file)
@@ -127,6 +127,7 @@ if ($hassiteconfig
                              'msnid' => new lang_string('msnid'),
                              'firstaccess' => new lang_string('firstaccess'),
                              'lastaccess' => new lang_string('lastaccess'),
+                             'lastip' => new lang_string('lastip'),
                              'mycourses' => new lang_string('mycourses'),
                              'groups' => new lang_string('groups'),
                              'suspended' => new lang_string('suspended', 'auth'),
index 558c848..b460b1a 100644 (file)
@@ -111,22 +111,32 @@ Feature: Set up contextual data for tests
     Then I should see "Topic 1"
 
   Scenario: Add role assigns
-    Given the following "users" exists:
+    Given the following "roles" exists:
+      | name                   | shortname | description      | archetype      |
+      | Custom editing teacher | custom1   | My custom role 1 | editingteacher |
+      | Custom student         | custom2   |                  |                |
+    And the following "users" exists:
       | username | firstname | lastname | email |
       | user1 | User | 1 | user1@moodlemoodle.com |
       | user2 | User | 2 | user2@moodlemoodle.com |
       | user3 | User | 3 | user3@moodlemoodle.com |
+      | user4 | User | 4 | user4@moodlemoodle.com |
+      | user5 | User | 5 | user5@moodlemoodle.com |
     And the following "categories" exists:
       | name | category | idnumber |
       | Cat 1 | 0 | CAT1 |
     And the following "courses" exists:
       | fullname | shortname | category |
       | Course 1 | C1 | CAT1 |
+    And the following "course enrolments" exists:
+      | user | course | role |
+      | user4 | C1 | custom1 |
     And the following "role assigns" exists:
       | user  | role           | contextlevel | reference |
       | user1 | manager        | System       |           |
       | user2 | editingteacher | Category     | CAT1      |
       | user3 | editingteacher | Course       | C1        |
+      | user5 | custom2        | System       |           |
     When I log in as "user1"
     Then I should see "Front page settings"
     And I log out
@@ -137,6 +147,16 @@ Feature: Set up contextual data for tests
     And I log in as "user3"
     And I follow "Course 1"
     And I should see "Turn editing on"
+    And I log out
+    And I log in as "user4"
+    And I follow "Course 1"
+    And I should see "Turn editing on"
+    And I log out
+    And I log in as "user5"
+    And I should see "You are logged in as"
+    And I follow "Course 1"
+    And I should see "You can not enrol yourself in this course."
+
 
   Scenario: Add modules
     Given the following "courses" exists:
index 7ae6017..ec4b117 100644 (file)
@@ -5,7 +5,9 @@
  *
  * Helps an admin to clean up spam in Moodle
  *
- * @authors Dongsheng Cai, Martin Dougiamas, Amr Hourani
+ * @author Dongsheng Cai
+ * @author Martin Dougiamas
+ * @author Amr Hourani
  * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  */
 
index 63f005b..ff06a3a 100644 (file)
@@ -422,6 +422,7 @@ class auth_plugin_cas extends auth_plugin_ldap {
 
         // Test for group creator
         if (!empty($this->config->groupecreators)) {
+            $ldapconnection = $this->ldap_connect();
             if ($this->config->memberattribute_isdn) {
                 if(!($userid = $this->ldap_find_userdn($ldapconnection, $extusername))) {
                     return false;
index 0f74ede..9004e26 100644 (file)
@@ -1534,6 +1534,7 @@ class auth_plugin_ldap extends auth_plugin_base {
             array_push($contexts, $this->config->create_context);
         }
 
+        $ldap_cookie = '';
         $ldap_pagedresults = ldap_paged_results_supported($this->config->ldap_version);
         foreach ($contexts as $context) {
             $context = trim($context);
index 1ee6e5e..21e8f6c 100644 (file)
@@ -216,7 +216,7 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
      * @return int
      */
     public static function get_supported_modes(array $configuration = array()) {
-        return self::MODE_APPLICATION + self::MODE_SESSION;
+        return self::MODE_APPLICATION;
     }
 
     /**
index 1bce7aa..2c601fe 100644 (file)
@@ -224,7 +224,7 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
      * @return int
      */
     public static function get_supported_modes(array $configuration = array()) {
-        return self::MODE_APPLICATION + self::MODE_SESSION;
+        return self::MODE_APPLICATION;
     }
 
     /**
index a6fd6a2..cdf764f 100644 (file)
@@ -175,7 +175,7 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
      * @return int
      */
     public static function get_supported_modes(array $configuration = array()) {
-        return self::MODE_APPLICATION + self::MODE_SESSION;
+        return self::MODE_APPLICATION;
     }
 
     /**
index 4a24f70..b837e7f 100644 (file)
@@ -8,6 +8,6 @@
     "require-dev": {
         "phpunit/phpunit": "3.7.*",
         "phpunit/dbUnit": "1.2.*",
-        "moodlehq/behat-extension": "1.27.3"
+        "moodlehq/behat-extension": "1.27.4"
     }
 }
index 6c97879..18d1a64 100644 (file)
@@ -201,18 +201,30 @@ class core_files_renderer extends plugin_renderer_base {
     <div class="fp-navbar">
         <div class="filemanager-toolbar">
             <div class="fp-toolbar">
-                <div class="{!}fp-btn-add"><a role="button" title="'.$straddfile.'" href="#"><img src="'.$this->pix_url('a/add_file').'" alt="" /></a></div>
-                <div class="{!}fp-btn-mkdir"><a role="button" title="'.$strmakedir.'" href="#"><img src="'.$this->pix_url('a/create_folder').'" alt="" /></a></div>
-                <div class="{!}fp-btn-download"><a role="button" title="'.$strdownload.'" href="#"><img src="'.$this->pix_url('a/download_all').'" alt="" /></a></div>
+                <div class="fp-btn-add">
+                    <a role="button" title="'.$straddfile.'" href="#"><img src="'.$this->pix_url('a/add_file').'" alt="" /></a>
+                </div>
+                <div class="fp-btn-mkdir">
+                    <a role="button" title="'.$strmakedir.'" href="#"><img src="'.$this->pix_url('a/create_folder').'" alt="" /></a>
+                </div>
+                <div class="fp-btn-download">
+                    <a role="button" title="'.$strdownload.'" href="#"><img src="'.$this->pix_url('a/download_all').'" alt="" /></a>
+                </div>
             </div>
-            <div class="{!}fp-viewbar">
-                <a title="'. get_string('displayicons', 'repository') .'" class="{!}fp-vb-icons" href="#"><img alt="" src="'. $this->pix_url('fp/view_icon_active', 'theme') .'" /></a>
-                <a title="'. get_string('displaydetails', 'repository') .'" class="{!}fp-vb-details" href="#"><img alt="" src="'. $this->pix_url('fp/view_list_active', 'theme') .'" /></a>
-                <a title="'. get_string('displaytree', 'repository') .'" class="{!}fp-vb-tree" href="#"><img alt="" src="'. $this->pix_url('fp/view_tree_active', 'theme') .'" /></a>
+            <div class="fp-viewbar">
+                <a title="'. get_string('displayicons', 'repository') .'" class="fp-vb-icons" href="#">
+                    <img alt="" src="'. $this->pix_url('fp/view_icon_active', 'theme') .'" />
+                </a>
+                <a title="'. get_string('displaydetails', 'repository') .'" class="fp-vb-details" href="#">
+                    <img alt="" src="'. $this->pix_url('fp/view_list_active', 'theme') .'" />
+                </a>
+                <a title="'. get_string('displaytree', 'repository') .'" class="fp-vb-tree" href="#">
+                    <img alt="" src="'. $this->pix_url('fp/view_tree_active', 'theme') .'" />
+                </a>
             </div>
         </div>
         <div class="fp-pathbar">
-            <span class="{!}fp-path-folder"><a class="{!}fp-path-folder-name" href="#"></a></span>
+            <span class="fp-path-folder"><a class="fp-path-folder-name" href="#"></a></span>
         </div>
     </div>
     <div class="filemanager-loading mdl-align">'.$icon_progress.'</div>
@@ -249,17 +261,17 @@ class core_files_renderer extends plugin_renderer_base {
 <div class="fp-file">
     <a href="#">
     <div style="position:relative;">
-        <div class="{!}fp-thumbnail"></div>
+        <div class="fp-thumbnail"></div>
         <div class="fp-reficons1"></div>
         <div class="fp-reficons2"></div>
     </div>
     <div class="fp-filename-field">
-        <div class="{!}fp-filename"></div>
+        <div class="fp-filename"></div>
     </div>
     </a>
-    <a class="{!}fp-contextmenu" href="#">'.$this->pix_icon('i/menu', '▶').'</a>
+    <a class="fp-contextmenu" href="#">'.$this->pix_icon('i/menu', '▶').'</a>
 </div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -279,14 +291,14 @@ class core_files_renderer extends plugin_renderer_base {
         $rv = '
 <span class="fp-filename-icon">
     <a href="#">
-    <span class="{!}fp-icon"></span>
+    <span class="fp-icon"></span>
     <span class="fp-reficons1"></span>
     <span class="fp-reficons2"></span>
-    <span class="{!}fp-filename"></span>
+    <span class="fp-filename"></span>
     </a>
-    <a class="{!}fp-contextmenu" href="#" onclick="return false;">'.$this->pix_icon('i/menu', '▶').'</a>
+    <a class="fp-contextmenu" href="#" onclick="return false;">'.$this->pix_icon('i/menu', '▶').'</a>
 </span>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -309,10 +321,10 @@ class core_files_renderer extends plugin_renderer_base {
         <label id="fp-mkdir-dlg-title">' . get_string('newfoldername', 'repository') . '</label><br/>
         <input type="text" />
     </div>
-    <button class="{!}fp-dlg-butcreate">'.get_string('makeafolder').'</button>
-    <button class="{!}fp-dlg-butcancel">'.get_string('cancel').'</button>
+    <button class="fp-dlg-butcreate btn-primary">'.get_string('makeafolder').'</button>
+    <button class="fp-dlg-butcancel btn-cancel">'.get_string('cancel').'</button>
 </div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -369,50 +381,78 @@ class core_files_renderer extends plugin_renderer_base {
     private function fm_js_template_fileselectlayout() {
         global $OUTPUT;
         $strloading  = get_string('loading', 'repository');
-        $icon_progress = $this->pix_icon('i/loading_small', $strloading).'';
+        $iconprogress = $this->pix_icon('i/loading_small', $strloading).'';
         $rv = '
 <div class="filemanager fp-select">
     <div class="fp-select-loading">
         <img src="'.$this->pix_url('i/loading_small').'" />
     </div>
-    <form>
-        <button class="{!}fp-file-download">'.get_string('download').'</button>
-        <button class="{!}fp-file-delete">'.get_string('delete').'</button>
-        <button class="{!}fp-file-setmain">'.get_string('setmainfile', 'repository').'</button><span class="fp-file-setmain-help">'.$OUTPUT->help_icon('setmainfile', 'repository').'</span>
-        <button class="{!}fp-file-zip">'.get_string('zip', 'editor').'</button>
-        <button class="{!}fp-file-unzip">'.get_string('unzip').'</button>
+    <form class="form-horizontal">
+        <button class="fp-file-download">'.get_string('download').'</button>
+        <button class="fp-file-delete">'.get_string('delete').'</button>
+        <button class="fp-file-setmain">'.get_string('setmainfile', 'repository').'</button>
+        <span class="fp-file-setmain-help">'.$OUTPUT->help_icon('setmainfile', 'repository').'</span>
+        <button class="fp-file-zip">'.get_string('zip', 'editor').'</button>
+        <button class="fp-file-unzip">'.get_string('unzip').'</button>
         <div class="fp-hr"></div>
-        <table>
-            <tr class="{!}fp-saveas"><td class="mdl-right"><label>'.get_string('name', 'moodle').'</label>:</td>
-            <td class="mdl-left"><input type="text"/></td></tr>
-            <tr class="{!}fp-author"><td class="mdl-right"><label>'.get_string('author', 'repository').'</label>:</td>
-            <td class="mdl-left"><input type="text"/></td></tr>
-            <tr class="{!}fp-license"><td class="mdl-right"><label>'.get_string('chooselicense', 'repository').'</label>:</td>
-            <td class="mdl-left"><select></select></td></tr>
-            <tr class="{!}fp-path"><td class="mdl-right"><label>'.get_string('path', 'moodle').'</label>:</td>
-            <td class="mdl-left"><select></select></td></tr>
-            <tr class="{!}fp-original"><td class="mdl-right"><label>'.get_string('original', 'repository').'</label>:</td>
-            <td class="mdl-left"><span class="fp-originloading">'.$icon_progress.' '.$strloading.'</span><span class="fp-value"></span></td></tr>
-            <tr class="{!}fp-reflist"><td class="mdl-right"><label>'.get_string('referenceslist', 'repository').'</label>:</td>
-            <td class="mdl-left"><p class="{!}fp-refcount"></p><span class="fp-reflistloading">'.$icon_progress.' '.$strloading.'</span><ul class="fp-value"></ul></td></tr>
-        </table>
+
+        <div class="fp-forminset">
+                <div class="fp-saveas control-group clearfix">
+                    <label class="control-label">'.get_string('name', 'repository').'</label>
+                    <div class="controls">
+                        <input type="text"/>
+                    </div>
+                </div>
+                <div class="fp-author control-group clearfix">
+                    <label class="control-label">'.get_string('author', 'repository').'</label>
+                    <div class="controls">
+                        <input type="text"/>
+                    </div>
+                </div>
+                <div class="fp-license control-group clearfix">
+                    <label class="control-label">'.get_string('chooselicense', 'repository').'</label>
+                    <div class="controls">
+                        <select></select>
+                    </div>
+                </div>
+                <div class="fp-path control-group clearfix">
+                    <label class="control-label">'.get_string('path', 'repository').'</label>
+                    <div class="controls">
+                        <select></select>
+                    </div>
+                </div>
+                <div class="fp-original control-group clearfix">
+                    <label class="control-label">'.get_string('original', 'repository').'</label>
+                    <div class="controls">
+                        <span class="fp-originloading">'.$iconprogress.' '.$strloading.'</span><span class="fp-value"></span>
+                    </div>
+                </div>
+                <div class="fp-reflist control-group clearfix">
+                    <label class="control-label">'.get_string('referenceslist', 'repository').'</label>
+                    <div class="controls">
+                        <p class="fp-refcount"></p>
+                        <span class="fp-reflistloading">'.$iconprogress.' '.$strloading.'</span>
+                        <ul class="fp-value"></ul>
+                    </div>
+                </div>
+        </div>
         <div class="fp-select-buttons">
-            <button class="{!}fp-file-update">'.get_string('update', 'moodle').'</button>
-            <button class="{!}fp-file-cancel">'.get_string('cancel').'</button>
+            <button class="fp-file-update btn-primary">'.get_string('update', 'moodle').'</button>
+            <button class="fp-file-cancel btn-cancel">'.get_string('cancel').'</button>
         </div>
     </form>
     <div class="fp-info clearfix">
         <div class="fp-hr"></div>
-        <p class="{!}fp-thumbnail"></p>
+        <p class="fp-thumbnail"></p>
         <div class="fp-fileinfo">
-            <div class="{!}fp-datemodified">'.get_string('lastmodified', 'moodle').': <span class="fp-value"></span></div>
-            <div class="{!}fp-datecreated">'.get_string('datecreated', 'repository').': <span class="fp-value"></span></div>
-            <div class="{!}fp-size">'.get_string('size', 'repository').': <span class="fp-value"></span></div>
-            <div class="{!}fp-dimensions">'.get_string('dimensions', 'repository').': <span class="fp-value"></span></div>
+            <div class="fp-datemodified">'.get_string('lastmodified', 'repository').' <span class="fp-value"></span></div>
+            <div class="fp-datecreated">'.get_string('datecreated', 'repository').' <span class="fp-value"></span></div>
+            <div class="fp-size">'.get_string('size', 'repository').' <span class="fp-value"></span></div>
+            <div class="fp-dimensions">'.get_string('dimensions', 'repository').' <span class="fp-value"></span></div>
         </div>
     </div>
 </div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -429,11 +469,11 @@ class core_files_renderer extends plugin_renderer_base {
     private function fm_js_template_confirmdialog() {
         $rv = '
 <div class="filemanager fp-dlg">
-    <div class="{!}fp-dlg-text"></div>
-    <button class="{!}fp-dlg-butconfirm">'.get_string('ok').'</button>
-    <button class="{!}fp-dlg-butcancel">'.get_string('cancel').'</button>
+    <div class="fp-dlg-text"></div>
+    <button class="fp-dlg-butconfirm btn-primary">'.get_string('ok').'</button>
+    <button class="fp-dlg-butcancel btn-cancel">'.get_string('cancel').'</button>
 </div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -525,36 +565,64 @@ class core_files_renderer extends plugin_renderer_base {
 <div tabindex="0" class="file-picker fp-generallayout" role="dialog" aria-live="assertive">
     <div class="fp-repo-area">
         <ul class="fp-list">
-            <li class="{!}fp-repo"><a href="#"><img class="{!}fp-repo-icon" alt=" " width="16" height="16" />&nbsp;<span class="{!}fp-repo-name"></span></a></li>
+            <li class="fp-repo">
+                <a href="#"><img class="fp-repo-icon" alt=" " width="16" height="16" />&nbsp;<span class="fp-repo-name"></span></a>
+            </li>
         </ul>
     </div>
     <div class="fp-repo-items" tabindex="0">
         <div class="fp-navbar">
             <div>
-                <div class="{!}fp-toolbar">
-                    <div class="{!}fp-tb-back"><a href="#">'.get_string('back', 'repository').'</a></div>
-                    <div class="{!}fp-tb-search"><form></form></div>
-                    <div class="{!}fp-tb-refresh"><a title="'. get_string('refresh', 'repository') .'" href="#"><img alt=""  src="'.$this->pix_url('a/refresh').'" /></a></div>
-                    <div class="{!}fp-tb-logout"><a title="'. get_string('logout', 'repository') .'" href="#"><img alt="" src="'.$this->pix_url('a/logout').'" /></a></div>
-                    <div class="{!}fp-tb-manage"><a title="'. get_string('settings', 'repository') .'" href="#"><img alt="" src="'.$this->pix_url('a/setting').'" /></a></div>
-                    <div class="{!}fp-tb-help"><a title="'. get_string('help', 'repository') .'" href="#"><img alt="" src="'.$this->pix_url('a/help').'" /></a></div>
-                    <div class="{!}fp-tb-message"></div>
+                <div class="fp-toolbar">
+                    <div class="fp-tb-back">
+                        <a href="#">'.get_string('back', 'repository').'</a>
+                    </div>
+                    <div class="fp-tb-search">
+                        <form></form>
+                    </div>
+                    <div class="fp-tb-refresh">
+                        <a title="'. get_string('refresh', 'repository') .'" href="#">
+                            <img alt=""  src="'.$this->pix_url('a/refresh').'" />
+                        </a>
+                    </div>
+                    <div class="fp-tb-logout">
+                        <a title="'. get_string('logout', 'repository') .'" href="#">
+                            <img alt="" src="'.$this->pix_url('a/logout').'" />
+                        </a>
+                    </div>
+                    <div class="fp-tb-manage">
+                        <a title="'. get_string('settings', 'repository') .'" href="#">
+                            <img alt="" src="'.$this->pix_url('a/setting').'" />
+                        </a>
+                    </div>
+                    <div class="fp-tb-help">
+                        <a title="'. get_string('help', 'repository') .'" href="#">
+                            <img alt="" src="'.$this->pix_url('a/help').'" />
+                        </a>
+                    </div>
+                    <div class="fp-tb-message"></div>
                 </div>
-                <div class="{!}fp-viewbar">
-                    <a title="'. get_string('displayicons', 'repository') .'" class="{!}fp-vb-icons" href="#"><img alt="" src="'. $this->pix_url('fp/view_icon_active', 'theme') .'" /></a>
-                    <a title="'. get_string('displaydetails', 'repository') .'" class="{!}fp-vb-details" href="#"><img alt="" src="'. $this->pix_url('fp/view_list_active', 'theme') .'" /></a>
-                    <a title="'. get_string('displaytree', 'repository') .'" class="{!}fp-vb-tree" href="#"><img alt="" src="'. $this->pix_url('fp/view_tree_active', 'theme') .'" /></a>
+                <div class="fp-viewbar">
+                    <a title="'. get_string('displayicons', 'repository') .'" class="fp-vb-icons" href="#">
+                        <img alt="" src="'. $this->pix_url('fp/view_icon_active', 'theme') .'" />
+                    </a>
+                    <a title="'. get_string('displaydetails', 'repository') .'" class="fp-vb-details" href="#">
+                        <img alt="" src="'. $this->pix_url('fp/view_list_active', 'theme') .'" />
+                    </a>
+                    <a title="'. get_string('displaytree', 'repository') .'" class="fp-vb-tree" href="#">
+                        <img alt="" src="'. $this->pix_url('fp/view_tree_active', 'theme') .'" />
+                    </a>
                 </div>
                 <div class="fp-clear-left"></div>
             </div>
             <div class="fp-pathbar">
-                 <span class="{!}fp-path-folder"><a class="{!}fp-path-folder-name" href="#"></a></span>
+                 <span class="fp-path-folder"><a class="fp-path-folder-name" href="#"></a></span>
             </div>
         </div>
-        <div class="{!}fp-content"></div>
+        <div class="fp-content"></div>
     </div>
 </div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -578,15 +646,15 @@ class core_files_renderer extends plugin_renderer_base {
         $rv = '
 <a class="fp-file" href="#" >
     <div style="position:relative;">
-        <div class="{!}fp-thumbnail"></div>
+        <div class="fp-thumbnail"></div>
         <div class="fp-reficons1"></div>
         <div class="fp-reficons2"></div>
     </div>
     <div class="fp-filename-field">
-        <p class="{!}fp-filename"></p>
+        <p class="fp-filename"></p>
     </div>
 </a>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -609,11 +677,11 @@ class core_files_renderer extends plugin_renderer_base {
         $rv = '
 <span class="fp-filename-icon">
     <a href="#">
-        <span class="{!}fp-icon"></span>
-        <span class="{!}fp-filename"></span>
+        <span class="fp-icon"></span>
+        <span class="fp-filename"></span>
     </a>
 </span>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -631,13 +699,13 @@ class core_files_renderer extends plugin_renderer_base {
      */
     private function fp_js_template_nextpage() {
         $rv = '
-<div class="{!}fp-nextpage">
+<div class="fp-nextpage">
     <div class="fp-nextpage-link"><a href="#">'.get_string('more').'</a></div>
     <div class="fp-nextpage-loading">
         <img src="'.$this->pix_url('i/loading_small').'" />
     </div>
 </div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -674,46 +742,64 @@ class core_files_renderer extends plugin_renderer_base {
     <div class="fp-select-loading">
         <img src="'.$this->pix_url('i/loading_small').'" />
     </div>
-    <form>
-        <table>
-            <tr class="{!}fp-linktype-2">
-                <td class="mdl-right"></td>
-                <td class="mdl-left"><input type="radio"/><label>&nbsp;'.get_string('makefileinternal', 'repository').'</label></td></tr>
-            <tr class="{!}fp-linktype-1">
-                <td class="mdl-right"></td>
-                <td class="mdl-left"><input type="radio"/><label>&nbsp;'.get_string('makefilelink', 'repository').'</label></td></tr>
-            <tr class="{!}fp-linktype-4">
-                <td class="mdl-right"></td>
-                <td class="mdl-left"><input type="radio"/><label>&nbsp;'.get_string('makefilereference', 'repository').'</label></td></tr>
-            <tr class="{!}fp-saveas">
-                <td class="mdl-right"><label>'.get_string('saveas', 'repository').'</label>:</td>
-                <td class="mdl-left"><input type="text"/></td></tr>
-            <tr class="{!}fp-setauthor">
-                <td class="mdl-right"><label>'.get_string('author', 'repository').'</label>:</td>
-                <td class="mdl-left"><input type="text" /></td></tr>
-            <tr class="{!}fp-setlicense">
-                <td class="mdl-right"><label>'.get_string('chooselicense', 'repository').'</label>:</td>
-                <td class="mdl-left"><select></select></td></tr>
-        </table>
-        <div class="fp-select-buttons">
-            <button class="{!}fp-select-confirm">'.get_string('getfile', 'repository').'</button>
-            <button class="{!}fp-select-cancel">'.get_string('cancel').'</button>
+    <form class="form-horizontal">
+        <div class="fp-forminset">
+                <div class="fp-linktype-2 control-group clearfix">
+                    <label class="control-label">'.get_string('makefileinternal', 'repository').'</label>
+                    <div class="controls">
+                        <input type="radio"/>
+                    </div>
+                </div>
+                <div class="fp-linktype-1 control-group clearfix">
+                    <label class="control-label">'.get_string('makefilelink', 'repository').'</label>
+                    <div class="controls">
+                        <input type="radio"/>
+                    </div>
+                </div>
+                <div class="fp-linktype-4 control-group clearfix">
+                    <label class="control-label">'.get_string('makefilereference', 'repository').'</label>
+                    <div class="controls">
+                        <input type="radio"/>
+                    </div>
+                </div>
+                <div class="fp-saveas control-group clearfix">
+                    <label class="control-label">'.get_string('saveas', 'repository').'</label>
+                    <div class="controls">
+                        <input type="text"/>
+                    </div>
+                </div>
+                <div class="fp-setauthor control-group clearfix">
+                    <label class="control-label">'.get_string('author', 'repository').'</label>
+                    <div class="controls">
+                        <input type="text"/>
+                    </div>
+                </div>
+                <div class="fp-setlicense control-group clearfix">
+                    <label class="control-label">'.get_string('chooselicense', 'repository').'</label>
+                    <div class="controls">
+                        <select></select>
+                    </div>
+                </div>
+        </div>
+       <div class="fp-select-buttons">
+            <button class="fp-select-confirm btn-primary">'.get_string('getfile', 'repository').'</button>
+            <button class="fp-select-cancel btn-cancel">'.get_string('cancel').'</button>
         </div>
     </form>
     <div class="fp-info clearfix">
         <div class="fp-hr"></div>
-        <p class="{!}fp-thumbnail"></p>
+        <p class="fp-thumbnail"></p>
         <div class="fp-fileinfo">
-            <div class="{!}fp-datemodified">'.get_string('lastmodified', 'moodle').': <span class="fp-value"></span></div>
-            <div class="{!}fp-datecreated">'.get_string('datecreated', 'repository').': <span class="fp-value"></span></div>
-            <div class="{!}fp-size">'.get_string('size', 'repository').': <span class="fp-value"></span></div>
-            <div class="{!}fp-license">'.get_string('license', 'moodle').': <span class="fp-value"></span></div>
-            <div class="{!}fp-author">'.get_string('author', 'repository').': <span class="fp-value"></span></div>
-            <div class="{!}fp-dimensions">'.get_string('dimensions', 'repository').': <span class="fp-value"></span></div>
+            <div class="fp-datemodified">'.get_string('lastmodified', 'moodle').'<span class="fp-value"></span></div>
+            <div class="fp-datecreated">'.get_string('datecreated', 'repository').'<span class="fp-value"></span></div>
+            <div class="fp-size">'.get_string('size', 'repository').'<span class="fp-value"></span></div>
+            <div class="fp-license">'.get_string('license', 'moodle').'<span class="fp-value"></span></div>
+            <div class="fp-author">'.get_string('author', 'repository').'<span class="fp-value"></span></div>
+            <div class="fp-dimensions">'.get_string('dimensions', 'repository').'<span class="fp-value"></span></div>
         </div>
     <div>
 </div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -736,28 +822,42 @@ class core_files_renderer extends plugin_renderer_base {
      */
     private function fp_js_template_uploadform() {
         $rv = '
-<div class="fp-upload-form mdl-align">
+<div class="fp-upload-form">
     <div class="fp-content-center">
-        <form enctype="multipart/form-data" method="POST">
-            <table >
-                <tr class="{!}fp-file">
-                    <td class="mdl-right"><label>'.get_string('attachment', 'repository').'</label>:</td>
-                    <td class="mdl-left"><input type="file"/></td></tr>
-                <tr class="{!}fp-saveas">
-                    <td class="mdl-right"><label>'.get_string('saveas', 'repository').'</label>:</td>
-                    <td class="mdl-left"><input type="text"/></td></tr>
-                <tr class="{!}fp-setauthor">
-                    <td class="mdl-right"><label>'.get_string('author', 'repository').'</label>:</td>
-                    <td class="mdl-left"><input type="text"/></td></tr>
-                <tr class="{!}fp-setlicense">
-                    <td class="mdl-right"><label>'.get_string('chooselicense', 'repository').'</label>:</td>
-                    <td class="mdl-left"><select></select></td></tr>
-            </table>
+        <form enctype="multipart/form-data" method="POST" class="form-horizontal">
+            <div class="fp-formset">
+                <div class="fp-file control-group clearfix">
+                    <label class="control-label">'.get_string('attachment', 'repository').'</label>
+                    <div class="controls">
+                        <input type="file"/>
+                    </div>
+                </div>
+                <div class="fp-saveas control-group clearfix">
+                    <label class="control-label">'.get_string('saveas', 'repository').'</label>
+                    <div class="controls">
+                        <input type="text"/>
+                    </div>
+                </div>
+                <div class="fp-setauthor control-group clearfix">
+                    <label class="control-label">'.get_string('author', 'repository').'</label>
+                    <div class="controls">
+                        <input type="text"/>
+                    </div>
+                </div>
+                <div class="fp-setlicense control-group clearfix">
+                    <label class="control-label">'.get_string('chooselicense', 'repository').'</label>
+                    <div class="controls">
+                        <select ></select>
+                    </div>
+                </div>
+            </div>
         </form>
-        <div><button class="{!}fp-upload-btn">'.get_string('upload', 'repository').'</button></div>
+        <div class="mdl-align">
+            <button class="fp-upload-btn btn-primary">'.get_string('upload', 'repository').'</button>
+        </div>
     </div>
 </div> ';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -785,8 +885,8 @@ class core_files_renderer extends plugin_renderer_base {
      */
     private function fp_js_template_error() {
         $rv = '
-<div class="fp-content-error" ><div class="{!}fp-error"></div></div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+<div class="fp-content-error" ><div class="fp-error"></div></div>';
+        return $rv;
     }
 
     /**
@@ -805,10 +905,10 @@ class core_files_renderer extends plugin_renderer_base {
     private function fp_js_template_message() {
         $rv = '
 <div class="file-picker fp-msg" role="alertdialog" aria-live="assertive" aria-labelledby="fp-msg-labelledby">
-    <p class="{!}fp-msg-text" id="fp-msg-labelledby"></p>
-    <button class="{!}fp-msg-butok">'.get_string('ok').'</button>
+    <p class="fp-msg-text" id="fp-msg-labelledby"></p>
+    <button class="fp-msg-butok btn-primary">'.get_string('ok').'</button>
 </div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -829,14 +929,14 @@ class core_files_renderer extends plugin_renderer_base {
     private function fp_js_template_processexistingfile() {
         $rv = '
 <div class="file-picker fp-dlg">
-    <p class="{!}fp-dlg-text"></p>
+    <p class="fp-dlg-text"></p>
     <div class="fp-dlg-buttons">
-        <button class="{!}fp-dlg-butoverwrite">'.get_string('overwrite', 'repository').'</button>
-        <button class="{!}fp-dlg-butrename"></button>
-        <button class="{!}fp-dlg-butcancel">'.get_string('cancel').'</button>
+        <button class="fp-dlg-butoverwrite">'.get_string('overwrite', 'repository').'</button>
+        <button class="fp-dlg-butrename"></button>
+        <button class="fp-dlg-butcancel">'.get_string('cancel').'</button>
     </div>
 </div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -856,15 +956,15 @@ class core_files_renderer extends plugin_renderer_base {
     private function fp_js_template_processexistingfilemultiple() {
         $rv = '
 <div class="file-picker fp-dlg">
-    <p class="{!}fp-dlg-text"></p>
-    <a class="{!}fp-dlg-butoverwrite fp-panel-button" href="#">'.get_string('overwrite', 'repository').'</a>
-    <a class="{!}fp-dlg-butcancel fp-panel-button" href="#">'.get_string('cancel').'</a>
-    <a class="{!}fp-dlg-butrename fp-panel-button" href="#"></a>
+    <p class="fp-dlg-text"></p>
+    <a class="fp-dlg-butoverwrite fp-panel-button" href="#">'.get_string('overwrite', 'repository').'</a>
+    <a class="fp-dlg-butcancel fp-panel-button" href="#">'.get_string('cancel').'</a>
+    <a class="fp-dlg-butrename fp-panel-button" href="#"></a>
     <br/>
-    <a class="{!}fp-dlg-butoverwriteall fp-panel-button" href="#">'.get_string('overwriteall', 'repository').'</a>
-    <a class="{!}fp-dlg-butrenameall fp-panel-button" href="#">'.get_string('renameall', 'repository').'</a>
+    <a class="fp-dlg-butoverwriteall fp-panel-button" href="#">'.get_string('overwriteall', 'repository').'</a>
+    <a class="fp-dlg-butrenameall fp-panel-button" href="#">'.get_string('renameall', 'repository').'</a>
 </div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
@@ -893,29 +993,35 @@ class core_files_renderer extends plugin_renderer_base {
         $rv = '
 <div class="fp-login-form">
     <div class="fp-content-center">
-        <form>
-            <table >
-                <tr class="{!}fp-login-popup">
-                    <td colspan="2">
-                        <label>'.get_string('popup', 'repository').'</label>
-                        <p class="fp-popup"><button class="{!}fp-login-popup-but">'.get_string('login', 'repository').'</button></p></td></tr>
-                <tr class="{!}fp-login-textarea">
-                    <td colspan="2"><p><textarea></textarea></p></td></tr>
-                <tr class="{!}fp-login-select">
-                    <td align="right"><label></label></td>
-                    <td align="left"><select></select></td></tr>
-                <tr class="{!}fp-login-input">
-                    <td class="label"><label></label></td>
-                    <td class="input"><input/></td></tr>
-                <tr class="{!}fp-login-radiogroup">
-                    <td align="right" width="30%" valign="top"><label></label></td>
-                    <td align="left" valign="top"><p class="{!}fp-login-radio"><input /> <label></label></p></td></tr>
-            </table>
-            <p><button class="{!}fp-login-submit">'.get_string('submit', 'repository').'</button></p>
+        <form class="form-horizontal">
+            <div class="fp-formset">
+                <div class="fp-login-popup control-group clearfix">
+                    <div class="controls fp-popup">
+                        <button class="fp-login-popup-but btn-primary">'.get_string('login', 'repository').'</button>
+                    </div>
+                </div>
+                <div class="fp-login-textarea control-group clearfix">
+                    <div class="controls"><textarea></textarea></div>
+                </div>
+                <div class="fp-login-select control-group clearfix">
+                    <label class="control-label"></label>
+
+                    <div class="controls"><select></select></div>
+                </div>
+                <div class="fp-login-input control-group clearfix">
+                    <label class="control-label"></label>
+                    <div class="controls"><input/></div>
+                </div>
+                <div class="fp-login-radiogroup control-group clearfix">
+                    <label class="control-label"></label>
+                    <div class="controls fp-login-radio"><input /> <label></label></div>
+                </div>
+            </div>
+            <p><button class="fp-login-submit btn-primary">'.get_string('submit', 'repository').'</button></p>
         </form>
     </div>
 </div>';
-        return preg_replace('/\{\!\}/', '', $rv);
+        return $rv;
     }
 
     /**
index 6ad6365..f049d02 100644 (file)
@@ -1003,6 +1003,7 @@ $string['languagegood'] = 'This language pack is up-to-date! :-)';
 $string['last'] = 'Last';
 $string['lastaccess'] = 'Last access';
 $string['lastedited'] = 'Last edited';
+$string['lastip'] = 'Last IP address';
 $string['lastlogin'] = 'Last login';
 $string['lastmodified'] = 'Last modified';
 $string['lastname'] = 'Surname';
index 15d32ad..c9246eb 100644 (file)
@@ -26,6 +26,7 @@ $string['addmorechoiceblanks'] = 'Blanks for {no} more choices';
 $string['addcategory'] = 'Add category';
 $string['adminreport'] = 'Report on possible problems in your question database.';
 $string['advancedsearchoptions'] = 'Search options';
+$string['alltries'] = 'All tries';
 $string['answers'] = 'Answers';
 $string['availableq'] = 'Available?';
 $string['badbase'] = 'Bad base before **: {$a}**';
@@ -93,8 +94,7 @@ $string['defaultinfofor'] = 'The default category for questions shared in contex
 $string['defaultmarkmustbepositive'] = 'The default mark must be positive.';
 $string['deletecoursecategorywithquestions'] = 'There are questions in the question bank associated with this course category. If you proceed, they will be deleted. You may wish to move them first, using the question bank interface.';
 $string['deletequestioncheck'] = 'Are you absolutely sure you want to delete \'{$a}\'?';
-$string['deletequestionscheck'] = '<p>Are you absolutely sure you want to delete the following questions?</p>
-<p>{$a}</p>';
+$string['deletequestionscheck'] = 'Are you absolutely sure you want to delete the following questions?<br /><br />{$a}';
 $string['deletingbehaviour'] = 'Deleting question behaviour \'{$a}\'';
 $string['deletingqtype'] = 'Deleting question type \'{$a}\'';
 $string['didnotmatchanyanswer'] = '[Did not match any answer]';
@@ -153,6 +153,7 @@ $string['fileformat'] = 'File format';
 $string['filesareacourse'] = 'the course files area';
 $string['filesareasite'] = 'the site files area';
 $string['filestomove'] = 'Move / copy files to {$a}?';
+$string['firsttry'] = 'First try';
 $string['flagged'] = 'Flagged';
 $string['flagthisquestion'] = 'Flag this question';
 $string['formquestionnotinids'] = 'Form contained question that is not in questionids';
@@ -185,6 +186,7 @@ $string['invalidgrade'] = 'Grades ({$a}) do not match grade options - question s
 $string['invalidpenalty'] = 'Invalid penalty';
 $string['invalidwizardpage'] = 'Incorrect or no wizard page specified!';
 $string['lastmodifiedby'] = 'Last modified by';
+$string['lasttry'] = 'Last try';
 $string['linkedfiledoesntexist'] = 'Linked file {$a} doesn\'t exist';
 $string['makechildof'] = 'Make child of \'{$a}\'';
 $string['maketoplevelitem'] = 'Move to top level';
@@ -427,6 +429,7 @@ $string['unknownquestioncatregory'] = 'Unknown question category: {$a}.';
 $string['unknownquestiontype'] = 'Unknown question type: {$a}.';
 $string['whethercorrect'] = 'Whether correct';
 $string['whethercorrect_help'] = 'This covers both the textual description \'Correct\', \'Partially correct\' or \'Incorrect\', and any coloured highlighting that conveys the same information.';
+$string['whichtries'] = 'Which tries';
 $string['withselected'] = 'With selected';
 $string['xoutofmax'] = '{$a->mark} out of {$a->max}';
 $string['yougotnright'] = 'You have correctly selected {$a->num}.';
index 287c25b..80767f7 100644 (file)
@@ -45,8 +45,8 @@ $string['areauserbackup'] = 'User backup';
 $string['areauserpersonal'] = 'Private files';
 $string['areauserprofile'] = 'Profile';
 $string['attachedfiles'] = 'Attached files';
-$string['attachment'] = 'Attachment';
-$string['author'] = 'Author';
+$string['attachment'] = 'Attachment:';
+$string['author'] = 'Author:';
 $string['back'] = '&laquo; Back';
 $string['backtodraftfiles'] = '&laquo; Back to draft files manager';
 $string['cachecleared'] = 'Cached files are removed';
@@ -82,11 +82,11 @@ $string['createinstance'] = 'Create a repository instance';
 $string['createrepository'] = 'Create a repository instance';
 $string['createxxinstance'] = 'Create "{$a}" instance';
 $string['date'] = 'Date';
-$string['datecreated'] = 'Created';
+$string['datecreated'] = 'Created:';
 $string['deleted'] = 'Repository deleted';
 $string['deleterepository'] = 'Delete this repository';
 $string['detailview'] = 'View details';
-$string['dimensions'] = 'Dimensions';
+$string['dimensions'] = 'Dimensions:';
 $string['disabled'] = 'Disabled';
 $string['displaydetails'] = 'Display folder with file details';
 $string['displayicons'] = 'Display folder with file icons';
@@ -129,7 +129,7 @@ $string['getfiletimeout'] = 'Get file timeout';
 $string['hidden'] = 'Hidden';
 $string['help'] = 'Help';
 $string['choosealink'] = 'Choose a link...';
-$string['chooselicense'] = 'Choose license';
+$string['chooselicense'] = 'Choose license:';
 $string['iconview'] = 'View as icons';
 $string['imagesize'] = '{$a->width} x {$a->height} px';
 $string['instance'] = 'instance';
@@ -145,10 +145,11 @@ $string['invalidrepositoryid'] = 'Invalid repository ID';
 $string['invalidparams'] = 'Invalid parameters';
 $string['isactive'] = 'Active?';
 $string['keyword'] = 'Keyword';
+$string['lastmodified'] = 'Last modified:';
 $string['linkexternal'] = 'Link external';
 $string['listview'] = 'View as list';
 $string['loading'] = 'Loading...';
-$string['login'] = 'Login';
+$string['login'] = 'Login to your account';
 $string['logout'] = 'Logout';
 $string['lostsource'] = 'Error. Source is missing. {$a}';
 $string['makefileinternal'] = 'Make a copy of the file';
@@ -158,6 +159,7 @@ $string['manage'] = 'Manage repositories';
 $string['manageurl'] = 'Manage';
 $string['manageuserrepository'] = 'Manage individual repository';
 $string['moving'] = 'Moving';
+$string['name'] = 'Name:';
 $string['newfolder'] = 'New folder';
 $string['newfoldername'] = 'New folder name:';
 $string['noenter'] = 'Nothing entered';
@@ -177,6 +179,7 @@ $string['operation'] = 'Operation';
 $string['on'] = 'Enabled and visible';
 $string['overwrite'] = 'Overwrite';
 $string['overwriteall'] = 'Overwrite all';
+$string['path'] = 'Path:';
 $string['personalrepositories'] = 'Available repository instances';
 $string['plugin'] = 'Repository plug-ins';
 $string['pluginerror'] = 'Errors in repository plugin.';
@@ -198,7 +201,7 @@ $string['repositorycourse'] = 'Course repositories';
 $string['repositoryicon'] = 'Repository icon';
 $string['repositoryerror'] = 'Remote repository returned error: {$a}';
 $string['save'] = 'Save';
-$string['saveas'] = 'Save as';
+$string['saveas'] = 'Save as:';
 $string['saved'] = 'Saved';
 $string['saving'] = 'Saving';
 $string['automatedbackup'] = 'Automated backups';
@@ -211,7 +214,7 @@ $string['setupdefaultplugins'] = 'Setting up default repository plugins';
 $string['setmainfile'] = 'Set main file';
 $string['setmainfile_help'] = 'If there are multiple files in the folder, the main file is the one that appears on the view page. Other files such as images or videos may be embedded in it. In filemanager the main file is indicated with a title in bold.';
 $string['siteinstances'] = 'Repositories instances of the site';
-$string['size'] = 'Size';
+$string['size'] = 'Size:';
 $string['submit'] = 'Submit';
 $string['sync'] = 'Sync';
 $string['syncfiletimeout'] = 'Sync file timeout';
index 043e0af..7215c9f 100644 (file)
@@ -8506,7 +8506,7 @@ class admin_setting_devicedetectregex extends admin_setting {
     public function output_html($data, $query='') {
         global $OUTPUT;
 
-        $out  = html_writer::start_tag('table', array('border' => 1, 'class' => 'generaltable'));
+        $out  = html_writer::start_tag('table', array('class' => 'generaltable'));
         $out .= html_writer::start_tag('thead');
         $out .= html_writer::start_tag('tr');
         $out .= html_writer::tag('th', get_string('devicedetectregexexpression', 'admin'));
index 56fd008..0ed5f0c 100644 (file)
@@ -46,7 +46,7 @@ function user_preference_allow_ajax_update($name, $paramtype) {
  * This should be used in combination with ajax_check_captured_output to
  * report any captured output to the user.
  *
- * @retrun Boolean Returns true on success or false on failure.
+ * @return Boolean Returns true on success or false on failure.
  */
 function ajax_capture_output() {
     // Start capturing output in case of broken plugins.
index ee3e01b..bedcf5f 100644 (file)
@@ -52,6 +52,15 @@ use Behat\Mink\Exception\ExpectationException as ExpectationException,
  */
 class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
 
+    /**
+     * Small timeout.
+     *
+     * A reduced timeout for cases where self::TIMEOUT is too much
+     * and a simple $this->getSession()->getPage()->find() could not
+     * be enough.
+     */
+    const REDUCED_TIMEOUT = 2;
+
     /**
      * The timeout for each Behat step (load page, wait for an element to load...).
      */
@@ -88,12 +97,13 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
      * @param mixed $locator It depends on the $selector, can be the xpath, a name, a css locator...
      * @param Exception $exception Otherwise we throw exception with generic info
      * @param NodeElement $node Spins around certain DOM node instead of the whole page
+     * @param int $timeout Forces a specific time out (in seconds).
      * @return NodeElement
      */
-    protected function find($selector, $locator, $exception = false, $node = false) {
+    protected function find($selector, $locator, $exception = false, $node = false, $timeout = false) {
 
         // Returns the first match.
-        $items = $this->find_all($selector, $locator, $exception, $node);
+        $items = $this->find_all($selector, $locator, $exception, $node, $timeout);
         return count($items) ? reset($items) : null;
     }
 
@@ -107,9 +117,10 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
      * @param mixed $locator It depends on the $selector, can be the xpath, a name, a css locator...
      * @param Exception $exception Otherwise we throw expcetion with generic info
      * @param NodeElement $node Spins around certain DOM node instead of the whole page
+     * @param int $timeout Forces a specific time out (in seconds). If 0 is provided the default timeout will be applied.
      * @return array NodeElements list
      */
-    protected function find_all($selector, $locator, $exception = false, $node = false) {
+    protected function find_all($selector, $locator, $exception = false, $node = false, $timeout = false) {
 
         // Generic info.
         if (!$exception) {
@@ -138,6 +149,17 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
             $params['node'] = $node;
         }
 
+        // How much we will be waiting for the element to appear.
+        if (!$timeout) {
+            $timeout = self::TIMEOUT;
+            $microsleep = false;
+        } else {
+            // Spinning each 0.1 seconds if the timeout was forced as we understand
+            // that is a special case and is good to refine the performance as much
+            // as possible.
+            $microsleep = true;
+        }
+
         // Waits for the node to appear if it exists, otherwise will timeout and throw the provided exception.
         return $this->spin(
             function($context, $args) {
@@ -170,8 +192,9 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
                 return $context->getSession()->getDriver()->find(implode('|', $unions));
             },
             $params,
-            self::TIMEOUT,
-            $exception
+            $timeout,
+            $exception,
+            $microsleep
         );
     }
 
@@ -569,7 +592,7 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
 
         // If there are no editors we don't need to wait.
         try {
-            $this->find('css', '.mceEditor');
+            $this->find('css', '.mceEditor', false, false, self::REDUCED_TIMEOUT);
         } catch (ElementNotFoundException $e) {
             return;
         }
index f1c5caa..b3537bb 100644 (file)
@@ -773,7 +773,7 @@ function notify_login_failures() {
 /**
  * Delete files and directories older than one week from directory provided by $CFG->tempdir.
  *
- * @exception Exception Failed reading/accessing file or directory
+ * @throws Exception Failed reading/accessing file or directory
  * @return bool True on successful file and directory deletion; otherwise, false on failure
  */
 function cron_delete_from_temp() {
index 4514423..d01ac6f 100644 (file)
@@ -505,6 +505,16 @@ $capabilities = array(
         'clonepermissionsfrom' => 'moodle/user:update'
     ),
 
+    'moodle/user:viewlastip' => array(
+        'riskbitmask' => RISK_PERSONAL,
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_USER,
+        'archetypes' => array(
+            'manager' => CAP_ALLOW
+        ),
+        'clonepermissionsfrom' => 'moodle/user:update'
+    ),
+
     'moodle/user:viewhiddendetails' => array(
 
         'riskbitmask' => RISK_PERSONAL,
index 1cb0188..bc6f592 100644 (file)
@@ -906,7 +906,15 @@ $services = array(
             'core_course_get_contents',
             'core_get_component_strings',
             'core_user_add_user_device',
-            'core_calendar_get_calendar_events'),
+            'core_calendar_get_calendar_events',
+            'core_enrol_get_users_courses',
+            'core_enrol_get_enrolled_users',
+            'core_user_get_users_by_id',
+            'core_webservice_get_site_info',
+            'core_notes_create_notes',
+            'core_user_get_course_user_profiles',
+            'core_enrol_get_enrolled_users',
+            'core_message_send_instant_messages'),
         'enabled' => 0,
         'restrictedusers' => 0,
         'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE,
index 8090bd6..7368dc8 100644 (file)
 
 defined('MOODLE_INTERNAL') || die();
 
+/**
+ * Adds a file upload to the log table so that clam can resolve the filename to the user later if necessary
+ *
+ * @deprecated since 2.7 - use new file picker instead
+ *
+ * @param string $newfilepath
+ * @param stdClass $course
+ * @param bool $nourl
+ */
+function clam_log_upload($newfilepath, $course=null, $nourl=false) {
+    debugging('clam_log_upload() is not supposed to be used any more, use new file picker instead', DEBUG_DEVELOPER);
+}
+
+/**
+ * This function logs to error_log and to the log table that an infected file has been found and what's happened to it.
+ *
+ * @deprecated since 2.7 - use new file picker instead
+ *
+ * @param string $oldfilepath
+ * @param string $newfilepath
+ * @param int $userid The user
+ */
+function clam_log_infected($oldfilepath='', $newfilepath='', $userid=0) {
+    debugging('clam_log_infected() is not supposed to be used any more, use new file picker instead', DEBUG_DEVELOPER);
+}
+
+/**
+ * Some of the modules allow moving attachments (glossary), in which case we need to hunt down an original log and change the path.
+ *
+ * @deprecated since 2.7 - use new file picker instead
+ *
+ * @param string $oldpath
+ * @param string $newpath
+ * @param boolean $update
+ */
+function clam_change_log($oldpath, $newpath, $update=true) {
+    debugging('clam_change_log() is not supposed to be used any more, use new file picker instead', DEBUG_DEVELOPER);
+}
+
+/**
+ * Replaces the given file with a string.
+ *
+ * @deprecated since 2.7 - infected files are now deleted in file picker
+ *
+ * @param string $file
+ * @return boolean
+ */
+function clam_replace_infected_file($file) {
+    debugging('clam_change_log() is not supposed to be used any more', DEBUG_DEVELOPER);
+    return false;
+}
+
 /**
  * Checks whether the password compatibility library will work with the current
  * version of PHP. This cannot be done using PHP version numbers since the fix
index 5cdc3f2..206da10 100644 (file)
@@ -122,7 +122,7 @@ abstract class database_exporter {
      * @see $check_schema is true), queries the database and calls
      * appropriate callbacks.
      *
-     * @exception dbtransfer_exception if any checking (e.g. database schema) fails
+     * @throws dbtransfer_exception if any checking (e.g. database schema) fails
      *
      * @param string $description a user description of the data.
      */
index 92b9ff2..d9cf1a7 100644 (file)
@@ -90,7 +90,7 @@ class database_importer {
      * operation, before any database changes are made. It will check the database
      * schema if @see check_schema is true
      *
-     * @exception dbtransfer_exception if any checking (e.g. database schema, Moodle
+     * @throws dbtransfer_exception if any checking (e.g. database schema, Moodle
      * version) fails
      *
      * @param float $version the version of the system which generated the data
@@ -131,8 +131,8 @@ class database_importer {
      * Callback function. Should be called only once per table import operation,
      * before any table changes are made. It will delete all table data.
      *
-     * @exception dbtransfer_exception an unknown table import is attempted
-     * @exception ddl_table_missing_exception if the table is missing
+     * @throws dbtransfer_exception an unknown table import is attempted
+     * @throws ddl_table_missing_exception if the table is missing
      *
      * @param string $tablename - the name of the table that will be imported
      * @param string $schemaHash - the hash of the xmldb_table schema of the table
@@ -191,7 +191,7 @@ class database_importer {
      * between @see begin_table_import and @see finish_table_import calls.
      * It will insert table data.
      *
-     * @exception dml_exception if data insert operation failed
+     * @throws dml_exception if data insert operation failed
      *
      * @param string $tablename - the name of the table in which data will be
      * imported
index b92b488..d17f306 100644 (file)
@@ -60,7 +60,7 @@ class file_xml_database_exporter extends xml_database_exporter {
      * Specific implementation for file exporting the database: it opens output stream, calls
      * superclass @see database_exporter::export_database() and closes output stream.
      *
-     * @exception dbtransfer_exception if any checking (e.g. database schema) fails
+     * @throws dbtransfer_exception if any checking (e.g. database schema) fails
      *
      * @param string $description a user description of the data.
      */
index cc2dc58..1b4133a 100644 (file)
@@ -51,7 +51,7 @@ class string_xml_database_exporter extends xml_database_exporter {
      * Specific implementation for memory exporting the database: it clear the buffer
      * and calls superclass @see database_exporter::export_database().
      *
-     * @exception dbtransfer_exception if any checking (e.g. database schema) fails
+     * @throws dbtransfer_exception if any checking (e.g. database schema) fails
      * @param string $description a user description of the data.
      * @return void
      */
index 92e39e5..61304f8 100644 (file)
@@ -121,7 +121,7 @@ class file_pool_content_exception extends file_exception {
  * Problem with records in the {files_reference} table.
  *
  * @package   core_files
- * @catehory  files
+ * @category  files
  * @copyright 2012 David Mudrak <david@moodle.com>
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index f75a75c..fa4294d 100644 (file)
@@ -345,16 +345,8 @@ abstract class moodleform {
                 continue;
             }
 
-/*
-  // TODO: rethink the file scanning MDL-19380
-            if ($CFG->runclamonupload) {
-                if (!clam_scan_moodle_file($_FILES[$elname], $COURSE)) {
-                    $errors[$elname] = $_FILES[$elname]['uploadlog'];
-                    unset($_FILES[$elname]);
-                    continue;
-                }
-            }
-*/
+            // NOTE: the viruses are scanned in file picker, no need to deal with them here.
+
             $filename = clean_param($_FILES[$elname]['name'], PARAM_FILE);
             if ($filename === '') {
                 // TODO: improve error message - wrong chars
index 04c6988..600714b 100644 (file)
@@ -774,22 +774,33 @@ class theme_config {
                 $plugins = core_component::get_plugin_list($type);
                 foreach ($plugins as $plugin=>$fulldir) {
                     if (!empty($excludes[$type]) and is_array($excludes[$type])
-                        and in_array($plugin, $excludes[$type])) {
+                            and in_array($plugin, $excludes[$type])) {
                         continue;
                     }
 
-                    $plugincontent = '';
+                    // Add main stylesheet.
                     $sheetfile = "$fulldir/styles.css";
                     if (is_readable($sheetfile)) {
                         $cssfiles['plugins'][$type.'_'.$plugin] = $sheetfile;
                     }
-                    $sheetthemefile = "$fulldir/styles_{$this->name}.css";
-                    if (is_readable($sheetthemefile)) {
-                        $cssfiles['plugins'][$type.'_'.$plugin.'_'.$this->name] = $sheetthemefile;
+
+                    // Create a list of candidate sheets from parents (direct parent last) and current theme.
+                    $candidates = array();
+                    foreach (array_reverse($this->parent_configs) as $parent_config) {
+                        $candidates[] = $parent_config->name;
                     }
+                    $candidates[] = $this->name;
+
+                    // Add the sheets found.
+                    foreach ($candidates as $candidate) {
+                        $sheetthemefile = "$fulldir/styles_{$candidate}.css";
+                        if (is_readable($sheetthemefile)) {
+                            $cssfiles['plugins'][$type.'_'.$plugin.'_'.$candidate] = $sheetthemefile;
+                        }
                     }
                 }
             }
+        }
 
         // find out wanted parent sheets
         $excludes = $this->resolve_excludes('parents_exclude_sheets');
index 3e4bc3f..74049b6 100644 (file)
@@ -1225,8 +1225,13 @@ class page_requirements_manager {
             $format = '-debug';
         }
 
+        $rollupversion = $CFG->yui3version;
+        if (!empty($CFG->yuipatchlevel)) {
+            $rollupversion .= '_' . $CFG->yuipatchlevel;
+        }
+
         $baserollups = array(
-            'rollup/' . $CFG->yui3version . "/yui-moodlesimple{$yuiformat}.js",
+            'rollup/' . $rollupversion . "/yui-moodlesimple{$yuiformat}.js",
             'rollup/' . $jsrev . "/mcore{$format}.js",
         );
 
index d8456f9..b59f242 100644 (file)
@@ -1787,7 +1787,6 @@ class moodle_page {
 
     /**
      * Ensure the theme has not been loaded yet. If it has an exception is thrown.
-     * @source
      *
      * @throws coding_exception
      */
index 1c918b4..0e42e12 100644 (file)
@@ -1701,7 +1701,7 @@ function stats_temp_table_drop() {
  *
  * @param timestart timestamp of the start time of logs view
  * @param timeend timestamp of the end time of logs view
- * @returns boolen success (true) or failure(false)
+ * @return boolen success (true) or failure(false)
  */
 function stats_temp_table_setup() {
     global $DB;
@@ -1724,7 +1724,7 @@ function stats_temp_table_setup() {
  *
  * @param timestart timestamp of the start time of logs view
  * @param timeend timestamp of the end time of logs view
- * @returns boolen success (true) or failure(false)
+ * @return boolen success (true) or failure(false)
  */
 function stats_temp_table_fill($timestart, $timeend) {
     global $DB;
@@ -1752,7 +1752,7 @@ function stats_temp_table_fill($timestart, $timeend) {
 /**
  * Deletes summary logs table for stats calculation
  *
- * @returns boolen success (true) or failure(false)
+ * @return boolen success (true) or failure(false)
  */
 function stats_temp_table_clean() {
     global $DB;
index 20dcf5a..d9550cb 100644 (file)
@@ -41,6 +41,7 @@ class testing_data_generator {
     protected $scalecount = 0;
     protected $groupcount = 0;
     protected $groupingcount = 0;
+    protected $rolecount = 0;
 
     /** @var array list of plugin generators */
     protected $generators = array();
@@ -656,6 +657,93 @@ EOD;
         return $DB->get_record('scale', array('id'=>$id), '*', MUST_EXIST);
     }
 
+    /**
+     * Creates a new role in the system.
+     *
+     * You can fill $record with the role 'name',
+     * 'shortname', 'description' and 'archetype'.
+     *
+     * If an archetype is specified it's capabilities,
+     * context where the role can be assigned and
+     * all other properties are copied from the archetype;
+     * if no archetype is specified it will create an
+     * empty role.
+     *
+     * @param array|stdClass $record
+     * @return int The new role id
+     */
+    public function create_role($record=null) {
+        global $DB;
+
+        $this->rolecount++;
+        $i = $this->rolecount;
+
+        $record = (array)$record;
+
+        if (empty($record['shortname'])) {
+            $record['shortname'] = 'role-' . $i;
+        }
+
+        if (empty($record['name'])) {
+            $record['name'] = 'Test role ' . $i;
+        }
+
+        if (empty($record['description'])) {
+            $record['description'] = 'Test role ' . $i . ' description';
+        }
+
+        if (empty($record['archetype'])) {
+            $record['archetype'] = '';
+        } else {
+            $archetypes = get_role_archetypes();
+            if (empty($archetypes[$record['archetype']])) {
+                throw new coding_exception('\'role\' requires the field \'archetype\' to specify a ' .
+                    'valid archetype shortname (editingteacher, student...)');
+            }
+        }
+
+        // Creates the role.
+        if (!$newroleid = create_role($record['name'], $record['shortname'], $record['description'], $record['archetype'])) {
+            throw new coding_exception('There was an error creating \'' . $record['shortname'] . '\' role');
+        }
+
+        // If no archetype was specified we allow it to be added to all contexts,
+        // otherwise we allow it in the archetype contexts.
+        if (!$record['archetype']) {
+            $contextlevels = array_keys(context_helper::get_all_levels());
+        } else {
+            // Copying from the archetype default rol.
+            $archetyperoleid = $DB->get_field(
+                'role',
+                'id',
+                array('shortname' => $record['archetype'], 'archetype' => $record['archetype'])
+            );
+            $contextlevels = get_role_contextlevels($archetyperoleid);
+        }
+        set_role_contextlevels($newroleid, $contextlevels);
+
+        if ($record['archetype']) {
+
+            // We copy all the roles the archetype can assign, override and switch to.
+            if ($record['archetype']) {
+                $types = array('assign', 'override', 'switch');
+                foreach ($types as $type) {
+                    $rolestocopy = get_default_role_archetype_allows($type, $record['archetype']);
+                    foreach ($rolestocopy as $tocopy) {
+                        $functionname = 'allow_' . $type;
+                        $functionname($newroleid, $tocopy);
+                    }
+                }
+            }
+
+            // Copying the archetype capabilities.
+            $sourcerole = $DB->get_record('role', array('id' => $archetyperoleid));
+            role_cap_duplicate($sourcerole, $newroleid);
+        }
+
+        return $newroleid;
+    }
+
     /**
      * Helper method which combines $defaults with the values specified in $record.
      * If $record is an object, it is converted to an array.
index 0a5b390..749770b 100644 (file)
@@ -130,6 +130,10 @@ class behat_data_generators extends behat_base {
         'cohorts' => array(
             'datagenerator' => 'cohort',
             'required' => array('idnumber')
+        ),
+        'roles' => array(
+            'datagenerator' => 'role',
+            'required' => array('shortname')
         )
     );
 
@@ -377,6 +381,22 @@ class behat_data_generators extends behat_base {
         $this->datagenerator->role_assign($data['roleid'], $data['userid'], $context->id);
     }
 
+    /**
+     * Creates a role.
+     *
+     * @param array $data
+     * @return void
+     */
+    protected function process_role($data) {
+
+        // We require the user to fill the role shortname.
+        if (empty($data['shortname'])) {
+            throw new Exception('\'role\' requires the field \'shortname\' to be specified');
+        }
+
+        $this->datagenerator->create_role($data);
+    }
+
     /**
      * Gets the user id from it's username.
      * @throws Exception
@@ -402,7 +422,7 @@ class behat_data_generators extends behat_base {
         global $DB;
 
         if (!$id = $DB->get_field('role', 'id', array('shortname' => $roleshortname))) {
-            throw new Exception('The specified role with shortname"' . $roleshortname . '" does not exist');
+            throw new Exception('The specified role with shortname "' . $roleshortname . '" does not exist');
         }
 
         return $id;
@@ -439,7 +459,7 @@ class behat_data_generators extends behat_base {
         global $DB;
 
         if (!$id = $DB->get_field('course', 'id', array('shortname' => $shortname))) {
-            throw new Exception('The specified course with shortname"' . $shortname . '" does not exist');
+            throw new Exception('The specified course with shortname "' . $shortname . '" does not exist');
         }
         return $id;
     }
index 5468b86..f3fdf37 100644 (file)
@@ -110,18 +110,20 @@ class behat_forms extends behat_base {
         // We ensure that all the editors are loaded and we can interact with them.
         $this->ensure_editors_are_loaded();
 
-        // behat_base::find() throws an exception if there are no elements, we should not fail a test because of this.
+        // We already know that we waited for the DOM and the JS to be loaded, even the editor
+        // so, we will use the reduced timeout as it is a common task and we should save time.
         try {
 
             // Expand fieldsets link.
-            $collapseexpandlink = $this->find('xpath', "//div[@class='collapsible-actions']" .
+            $xpath = "//div[@class='collapsible-actions']" .
                 "/descendant::a[contains(concat(' ', @class, ' '), ' collapseexpand ')]" .
-                "[not(contains(concat(' ', @class, ' '), ' collapse-all '))]"
-            );
+                "[not(contains(concat(' ', @class, ' '), ' collapse-all '))]";
+            $collapseexpandlink = $this->find('xpath', $xpath, false, false, self::REDUCED_TIMEOUT);
             $collapseexpandlink->click();
 
         } catch (ElementNotFoundException $e) {
-            // We continue if there are not expandable fields.
+            // The behat_base::find() method throws an exception if there are no elements,
+            // we should not fail a test because of this. We continue if there are not expandable fields.
         }
 
         // Different try & catch as we can have expanded fieldsets with advanced fields on them.
@@ -132,7 +134,9 @@ class behat_forms extends behat_base {
                 "[contains(concat(' ', normalize-space(@class), ' '), ' moreless-toggler')]";
 
             // We don't wait here as we already waited when getting the expand fieldsets links.
-            $showmores = $this->getSession()->getPage()->findAll('xpath', $showmorexpath);
+            if (!$showmores = $this->getSession()->getPage()->findAll('xpath', $showmorexpath)) {
+                return;
+            }
 
             // Funny thing about this, with findAll() we specify a pattern and each element matching the pattern is added to the array
             // with of xpaths with a [0], [1]... sufix, but when we click on an element it does not matches the specified xpath
index 476650b..6134ab5 100644 (file)
@@ -346,10 +346,12 @@ class behat_general extends behat_base {
     }
 
     /**
-     * Checks, that the specified element is not visible. Only available in tests using Javascript.
+     * Checks, that the existing element is not visible. Only available in tests using Javascript.
      *
-     * As a "not" method, it's performance is not specially good as we should ensure that the element
-     * have time to appear.
+     * As a "not" method, it's performance could not be good, but in this
+     * case the performance is good because the element must exist,
+     * otherwise there would be a ElementNotFoundException, also here we are
+     * not spinning until the element is visible.
      *
      * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>(?:[^"]|\\")*)" should not be visible$/
      * @throws ElementNotFoundException
@@ -396,7 +398,12 @@ class behat_general extends behat_base {
     }
 
     /**
-     * Checks, that the specified element is not visible inside the specified container. Only available in tests using Javascript.
+     * Checks, that the existing element is not visible inside the existing container. Only available in tests using Javascript.
+     *
+     * As a "not" method, it's performance could not be good, but in this
+     * case the performance is good because the element must exist,
+     * otherwise there would be a ElementNotFoundException, also here we are
+     * not spinning until the element is visible.
      *
      * @Then /^"(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" in the "(?P<element_container_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)" should not be visible$/
      * @throws ElementNotFoundException
@@ -447,7 +454,8 @@ class behat_general extends behat_base {
         }
 
         // We spin as we don't have enough checking that the element is there, we
-        // should also ensure that the element is visible.
+        // should also ensure that the element is visible. Using microsleep as this
+        // is a repeated step and global performance is important.
         $this->spin(
             function($context, $args) {
 
@@ -460,7 +468,10 @@ class behat_general extends behat_base {
                 // If non of the nodes is visible we loop again.
                 throw new ExpectationException('"' . $args['text'] . '" text was found but was not visible', $context->getSession());
             },
-            array('nodes' => $nodes, 'text' => $text)
+            array('nodes' => $nodes, 'text' => $text),
+            false,
+            false,
+            true
         );
 
     }
@@ -481,9 +492,10 @@ class behat_general extends behat_base {
             "[count(descendant::*[contains(., $xpathliteral)]) = 0]";
 
         // We should wait a while to ensure that the page is not still loading elements.
-        // Giving preference to the reliability of the results rather than to the performance.
+        // Waiting less than self::TIMEOUT as we already waited for the DOM to be ready and
+        // all JS to be executed.
         try {
-            $nodes = $this->find_all('xpath', $xpath);
+            $nodes = $this->find_all('xpath', $xpath, false, false, self::REDUCED_TIMEOUT);
         } catch (ElementNotFoundException $e) {
             // All ok.
             return;
@@ -508,7 +520,10 @@ class behat_general extends behat_base {
                 // If non of the found nodes is visible we consider that the text is not visible.
                 return true;
             },
-            array('nodes' => $nodes, 'text' => $text)
+            array('nodes' => $nodes, 'text' => $text),
+            self::REDUCED_TIMEOUT,
+            false,
+            true
         );
 
     }
@@ -547,7 +562,8 @@ class behat_general extends behat_base {
             return;
         }
 
-        // We also check the element visibility when running JS tests.
+        // We also check the element visibility when running JS tests. Using microsleep as this
+        // is a repeated step and global performance is important.
         $this->spin(
             function($context, $args) {
 
@@ -559,7 +575,10 @@ class behat_general extends behat_base {
 
                 throw new ExpectationException('"' . $args['text'] . '" text was found in the "' . $args['element'] . '" element but was not visible', $context->getSession());
             },
-            array('nodes' => $nodes, 'text' => $text, 'element' => $element)
+            array('nodes' => $nodes, 'text' => $text, 'element' => $element),
+            false,
+            false,
+            true
         );
     }
 
@@ -587,7 +606,7 @@ class behat_general extends behat_base {
         // We should wait a while to ensure that the page is not still loading elements.
         // Giving preference to the reliability of the results rather than to the performance.
         try {
-            $nodes = $this->find_all('xpath', $xpath, false, $container);
+            $nodes = $this->find_all('xpath', $xpath, false, $container, self::REDUCED_TIMEOUT);
         } catch (ElementNotFoundException $e) {
             // All ok.
             return;
@@ -612,7 +631,10 @@ class behat_general extends behat_base {
                 // If all the found nodes are hidden we are happy.
                 return true;
             },
-            array('nodes' => $nodes, 'text' => $text, 'element' => $element)
+            array('nodes' => $nodes, 'text' => $text, 'element' => $element),
+            self::REDUCED_TIMEOUT,
+            false,
+            true
         );
     }
 
@@ -771,8 +793,28 @@ class behat_general extends behat_base {
      */
     public function should_not_exists($element, $selectortype) {
 
+        // Getting Mink selector and locator.
+        list($selector, $locator) = $this->transform_selector($selectortype, $element);
+
         try {
-            $this->should_exists($element, $selectortype);
+
+            // Using directly the spin method as we want a reduced timeout but there is no
+            // need for a 0.1 seconds interval because in the optimistic case we will timeout.
+            $params = array('selector' => $selector, 'locator' => $locator);
+            // The exception does not really matter as we will catch it and will never "explode".
+            $exception = new ElementNotFoundException($this->getSession(), $selectortype, null, $element);
+
+            // If all goes good it will throw an ElementNotFoundExceptionn that we will catch.
+            $this->spin(
+                function($context, $args) {
+                    return $context->getSession()->getPage()->findAll($args['selector'], $args['locator']);
+                },
+                $params,
+                false,
+                $exception,
+                self::REDUCED_TIMEOUT
+            );
+
             throw new ExpectationException('The "' . $element . '" "' . $selectortype . '" exists in the current page', $this->getSession());
         } catch (ElementNotFoundException $e) {
             // It passes.
@@ -828,8 +870,20 @@ class behat_general extends behat_base {
      * @param string $containerselectortype The container locator
      */
     public function should_not_exist_in_the($element, $selectortype, $containerelement, $containerselectortype) {
+
+        // Get the container node; here we throw an exception
+        // if the container node does not exist.
+        $containernode = $this->get_selected_node($containerselectortype, $containerelement);
+
+        list($selector, $locator) = $this->transform_selector($selectortype, $element);
+
+        // Will throw an ElementNotFoundException if it does not exist, but, actually
+        // it should not exists, so we try & catch it.
         try {
-            $this->should_exist_in_the($element, $selectortype, $containerelement, $containerselectortype);
+            // Would be better to use a 1 second sleep because the element should not be there,
+            // but we would need to duplicate the whole find_all() logic to do it, the benefit of
+            // changing to 1 second sleep is not significant.
+            $this->find($selector, $locator, false, $containernode, self::REDUCED_TIMEOUT);
             throw new ExpectationException('The "' . $element . '" "' . $selectortype . '" exists in the "' .
                 $containerelement . '" "' . $containerselectortype . '"', $this->getSession());
         } catch (ElementNotFoundException $e) {
index 6ac31a6..00485d1 100644 (file)
@@ -358,7 +358,7 @@ class behat_hooks extends behat_base {
      * This is used for content such as the DOM, and screenshots.
      *
      * @param StepEvent $event
-     * @param String $filetype The file suffix to use.
+     * @param String $filetype The file suffix to use. Limited to 4 chars.
      */
     protected function get_faildump_filename(StepEvent $event, $filetype) {
         global $CFG;
@@ -381,7 +381,11 @@ class behat_hooks extends behat_base {
         // The scenario title + the failed step text.
         // We want a i-am-the-scenario-title_i-am-the-failed-step.$filetype format.
         $filename = $event->getStep()->getParent()->getTitle() . '_' . $event->getStep()->getText();
-        $filename = preg_replace('/([^a-zA-Z0-9\_]+)/', '-', $filename) . '.' . $filetype;
+        $filename = preg_replace('/([^a-zA-Z0-9\_]+)/', '-', $filename);
+
+        // File name limited to 256 characters. Leaving 4 chars for the file
+        // extension as we allow .png for images and .html for DOM contents.
+        $filename = substr($filename, 0, 251) . '.' . $filetype;
 
         return array($dir, $filename);
     }
index f6bc851..7e6e207 100644 (file)
@@ -29,6 +29,8 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * This class handles all aspects of fileuploading
  *
+ * @deprecated since 2.7 - use new file pickers instead
+ *
  * @package   moodlecore
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -86,10 +88,11 @@ class upload_manager {
      * @param boolean $allownull Whether we care if there's no file when we've set the input name.
      * @param boolean $allownullmultiple Whether we care if there's no files AT ALL  when we've got multiples. This won't complain if we have file 1 and file 3 but not file 2, only for NO FILES AT ALL.
      */
-    function upload_manager($inputname='', $deleteothers=false, $handlecollisions=false, $course=null, $recoverifmultiple=false, $modbytes=0, $silent=false, $allownull=false, $allownullmultiple=true) {
-
+    function __construct($inputname='', $deleteothers=false, $handlecollisions=false, $course=null, $recoverifmultiple=false, $modbytes=0, $silent=false, $allownull=false, $allownullmultiple=true) {
         global $CFG, $SITE;
 
+        debugging('upload_manager class is deprecated, use new file picker instead', DEBUG_DEVELOPER);
+
         if (empty($course->id)) {
             $course = $SITE;
         }
@@ -233,7 +236,7 @@ class upload_manager {
                 $destination = substr($destination, 0, -1);
             }
 
-            if (!make_upload_directory($destination, true)) { //TODO maybe put this function here instead of moodlelib.php now.
+            if (!make_upload_directory($destination, true)) {
                 $this->status = false;
                 return false;
             }
@@ -258,8 +261,6 @@ class upload_manager {
                     $this->files[$i]['uploadlog'] .= "\n".get_string('uploadedfile');
                     $this->files[$i]['saved'] = true;
                     $exceptions[] = $this->files[$i]['name'];
-                    // now add it to the log (this is important so we know who to notify if a virus is found later on)
-                    clam_log_upload($this->files[$i]['fullpath'], $this->course);
                     $savedsomething=true;
                 }
             }
@@ -384,7 +385,6 @@ class upload_manager {
      *
      * @param object $file Passed in by reference. The current file from $files we're processing.
      * @return string
-     * @todo Finish documenting this function
      */
     function get_file_upload_error(&$file) {
 
@@ -511,25 +511,27 @@ UPLOAD_PRINT_FORM_FRAGMENT DOESN'T REALLY BELONG IN THE CLASS BUT CERTAINLY IN T
  *
  * If moving it fails, it deletes it.
  *
- * @global object
- * @global object
+ * @deprecated since 2.7 - to be removed together with the upload_manager above
+ *
  * @param string $file Full path to the file
  * @param int $userid If not used, defaults to $USER->id (there in case called from cron)
  * @param boolean $basiconly Admin level reporting or user level reporting.
  * @return string Details of what the function did.
  */
 function clam_handle_infected_file($file, $userid=0, $basiconly=false) {
-
     global $CFG, $USER;
+
+    debugging('clam_handle_infected_file() is not supposed to be used, the files are now scanned in file picker', DEBUG_DEVELOPER);
+
     if ($USER && !$userid) {
         $userid = $USER->id;
     }
     $delete = true;
+    $notice = '';
     if (file_exists($CFG->quarantinedir) && is_dir($CFG->quarantinedir) && is_writable($CFG->quarantinedir)) {
         $now = date('YmdHis');
         if (rename($file, $CFG->quarantinedir .'/'. $now .'-user-'. $userid .'-infected')) {
             $delete = false;
-            clam_log_infected($file, $CFG->quarantinedir.'/'. $now .'-user-'. $userid .'-infected', $userid);
             if ($basiconly) {
                 $notice .= "\n". get_string('clammovedfilebasic');
             }
@@ -556,7 +558,6 @@ function clam_handle_infected_file($file, $userid=0, $basiconly=false) {
     }
     if ($delete) {
         if (unlink($file)) {
-            clam_log_infected($file, '', $userid);
             $notice .= "\n". get_string('clamdeletedfile');
         }
         else {
@@ -572,44 +573,20 @@ function clam_handle_infected_file($file, $userid=0, $basiconly=false) {
     return $notice;
 }
 
-/**
- * Replaces the given file with a string.
- *
- * The replacement string is used to notify that the original file had a virus
- * This is to avoid missing files but could result in the wrong content-type.
- *
- * @param string $file Full path to the file.
- * @return boolean
- */
-function clam_replace_infected_file($file) {
-    global $CFG;
-
-    $newcontents = get_string('virusplaceholder');
-    if (!$f = fopen($file, 'w')) {
-        return false;
-    }
-    if (!fwrite($f, $newcontents)) {
-        return false;
-    }
-    @chmod($file, $CFG->filepermissions);
-    return true;
-}
-
-
 /**
  * If $CFG->runclamonupload is set, we scan a given file. (called from {@link preprocess_files()})
  *
- * This function will add on a uploadlog index in $file.
+ * @deprecated since 2.7 - to be removed together with the upload_manager above
  *
- * @global object
- * @global object
  * @param mixed $file The file to scan from $files. or an absolute path to a file.
- * @param course $course {@link $COURSE}
+ * @param stdClass $course
  * @return int 1 if good, 0 if something goes wrong (opposite from actual error code from clam)
  */
 function clam_scan_moodle_file(&$file, $course) {
     global $CFG, $USER;
 
+    debugging('clam_scan_moodle_file() is not supposed to be used, the files are now scanned in file picker', DEBUG_DEVELOPER);
+
     if (is_array($file) && is_uploaded_file($file['tmp_name'])) { // it's from $_FILES
         $appendlog = true;
         $fullpath = $file['tmp_name'];
@@ -671,7 +648,7 @@ function clam_scan_moodle_file(&$file, $course) {
         return false; // in this case, 0 means bad.
     default:
         // error - clam failed to run or something went wrong
-        $notice .= get_string('clamfailed', 'moodle', get_clam_error_code($return));
+        $notice = get_string('clamfailed', 'moodle', get_clam_error_code($return));
         $notice .= "\n\n". implode("\n", $output);
         $newreturn = true;
         if ($CFG->clamfailureonupload == 'actlikevirus') {
@@ -713,12 +690,11 @@ function clam_message_admins($notice) {
     }
 }
 
-
 /**
  * Returns the string equivalent of a numeric clam error code
  *
  * @param int $returncode The numeric error code in question.
- * return string The definition of the error code
+ * @return string The definition of the error code
  */
 function get_clam_error_code($returncode) {
     $returncodes = array();
@@ -745,77 +721,4 @@ function get_clam_error_code($returncode) {
     if ($returncodes[$returncode])
        return $returncodes[$returncode];
     return get_string('clamunknownerror');
-
-}
-
-/**
- * Adds a file upload to the log table so that clam can resolve the filename to the user later if necessary
- *
- * @global object
- * @global object
- * @param string $newfilepath ?
- * @param course $course {@link $COURSE}
- * @param boolean $nourl ?
- * @todo Finish documenting this function
- */
-function clam_log_upload($newfilepath, $course=null, $nourl=false) {
-    global $CFG, $USER;
-    // get rid of any double // that might have appeared
-    $newfilepath = preg_replace('/\/\//', '/', $newfilepath);
-    if (strpos($newfilepath, $CFG->dataroot) === false) {
-        $newfilepath = $CFG->dataroot .'/'. $newfilepath;
-    }
-    $courseid = 0;
-    if ($course) {
-        $courseid = $course->id;
-    }
-    add_to_log($courseid, 'upload', 'upload', ((!$nourl) ? substr($_SERVER['HTTP_REFERER'], 0, 100) : ''), $newfilepath);
-}
-
-/**
- * This function logs to error_log and to the log table that an infected file has been found and what's happened to it.
- *
- * @global object
- * @param string $oldfilepath Full path to the infected file before it was moved.
- * @param string $newfilepath Full path to the infected file since it was moved to the quarantine directory (if the file was deleted, leave empty).
- * @param int $userid The user id of the user who uploaded the file.
- */
-function clam_log_infected($oldfilepath='', $newfilepath='', $userid=0) {
-    global $DB;
-
-    add_to_log(0, 'upload', 'infected', $_SERVER['HTTP_REFERER'], $oldfilepath, 0, $userid);
-
-    $user = $DB->get_record('user', array('id'=>$userid));
-
-    $errorstr = 'Clam AV has found a file that is infected with a virus. It was uploaded by '
-        . ((empty($user)) ? ' an unknown user ' : fullname($user))
-        . ((empty($oldfilepath)) ? '. The infected file was caught on upload ('.$oldfilepath.')'
-           : '. The original file path of the infected file was '. $oldfilepath)
-        . ((empty($newfilepath)) ? '. The file has been deleted ' : '. The file has been moved to a quarantine directory and the new path is '. $newfilepath);
-
-    error_log($errorstr);
-}
-
-
-/**
- * Some of the modules allow moving attachments (glossary), in which case we need to hunt down an original log and change the path.
- *
- * @global object
- * @param string $oldpath The old path to the file (should be in the log)
- * @param string $newpath The new path to the file
- * @param boolean $update If true this function will overwrite old record (used for forum moving etc).
- */
-function clam_change_log($oldpath, $newpath, $update=true) {
-    global $DB;
-
-    if (!$record = $DB->get_record('log', array('info'=>$oldpath, 'module'=>'upload'))) {
-        return false;
-    }
-    $record->info = $newpath;
-    if ($update) {
-        $DB->update_record('log', $record);
-    } else {
-        unset($record->id);
-        $DB->insert_record('log', $record);
-    }
 }
index 69ab2e7..e3e3b8f 100644 (file)
Binary files a/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-debug.js and b/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-debug.js differ
index 3826d94..ccf1249 100644 (file)
Binary files a/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-min.js and b/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-min.js differ
index 69ab2e7..e3e3b8f 100644 (file)
Binary files a/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue.js and b/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue.js differ
index 72f62e6..69d3368 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js and b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js differ
index da31e22..01dc98c 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js and b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js differ
index 3bc5dd3..8df5bf6 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.js and b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.js differ
index 74972f7..fc7007e 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 7697ff3..b9033c5 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 74972f7..fc7007e 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
diff --git a/lib/yui/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose-debug.js b/lib/yui/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose-debug.js
new file mode 100644 (file)
index 0000000..39e057a
Binary files /dev/null and b/lib/yui/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose-debug.js differ
diff --git a/lib/yui/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose-min.js b/lib/yui/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose-min.js
new file mode 100644 (file)
index 0000000..ee027b0
Binary files /dev/null and b/lib/yui/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose-min.js differ
diff --git a/lib/yui/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose.js b/lib/yui/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose.js
new file mode 100644 (file)
index 0000000..b4fd9b5
Binary files /dev/null and b/lib/yui/build/moodle-core-widget-focusafterclose/moodle-core-widget-focusafterclose.js differ
index 7944b8b..663cbe7 100644 (file)
@@ -45,6 +45,7 @@ Y.extend(CHOOSERDIALOGUE, Y.Base, {
             modal: true, // This dialogue should be modal.
             shim : true,
             closeButtonTitle : this.get('closeButtonTitle'),
+            focusOnPreviousTargetAfterHide: true,
             render : false
         };
 
@@ -153,7 +154,7 @@ Y.extend(CHOOSERDIALOGUE, Y.Base, {
         this.options.removeAttribute('disabled');
 
         // Display the panel
-        this.panel.show();
+        this.panel.show(e);
 
         // Re-centre the dialogue after we've shown it.
         this.center_dialogue(dialogue);
index bc684e4..34c8210 100644 (file)
@@ -558,4 +558,6 @@ Y.Base.modifyAttrs(DIALOGUE, {
     }
 });
 
+Y.Base.mix(DIALOGUE, [Y.M.core.WidgetFocusAfterHide]);
+
 M.core.dialogue = DIALOGUE;
index c3c0bfe..db9bd7a 100644 (file)
@@ -15,6 +15,7 @@
         "panel",
         "event-key",
         "dd-plugin",
+        "moodle-core-widget-focusafterclose",
         "moodle-core-lockscroll"
     ]
   },
index f89bbf5..42bdb19 100644 (file)
@@ -313,7 +313,6 @@ Y.extend(TOOLTIP, M.core.dialogue, {
 
         // Prevent the default click action and prevent the event triggering anything else.
         e.preventDefault();
-        e.stopPropagation();
 
         // Cancel any existing listeners and close the panel if it's already open.
         this.cancel_events();
@@ -329,7 +328,7 @@ Y.extend(TOOLTIP, M.core.dialogue, {
         });
 
         // Now that initial setup has begun, show the panel.
-        this.show();
+        this.show(e);
 
         // Align with the link that was clicked.
         this.align(clickedlink, this.alignpoints);
@@ -455,6 +454,10 @@ Y.Base.modifyAttrs(TOOLTIP, {
      */
     modal: {
         value: false
+    },
+
+    focusOnPreviousTargetAfterHide: {
+        value: true
     }
 });
 
diff --git a/lib/yui/src/widget-focusafterclose/build.json b/lib/yui/src/widget-focusafterclose/build.json
new file mode 100644 (file)
index 0000000..05b26ae
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "name": "moodle-core-widget-focusafterclose",
+    "builds": {
+        "moodle-core-widget-focusafterclose": {
+            "jsfiles": [
+                "focusafter.js"
+            ]
+        }
+    }
+}
diff --git a/lib/yui/src/widget-focusafterclose/js/focusafter.js b/lib/yui/src/widget-focusafterclose/js/focusafter.js
new file mode 100644 (file)
index 0000000..112503e
--- /dev/null
@@ -0,0 +1,171 @@
+/**
+ * Provides support for focusing on different nodes after the Widget is
+ * hidden.
+ *
+ * If the focusOnPreviousTargetAfterHide attribute is true, then the module hooks
+ * into the show function for that Widget to try and determine which Node
+ * caused the Widget to be shown.
+ *
+ * Alternatively, the focusAfterHide attribute can be passed a Node.
+ *
+ * @module moodle-core-widget-focusafterhide
+ */
+
+var CAN_RECEIVE_FOCUS_SELECTOR = 'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex], [contenteditable="true"]';
+
+/**
+ * Provides support for focusing on different nodes after the Widget is
+ * hidden.
+ *
+ * @class M.core.WidgetFocusAfterHide
+ */
+function WidgetFocusAfterHide() {
+    Y.after(this._bindUIFocusAfterHide, this, 'bindUI');
+    if (this.get('rendered')) {
+        this._bindUIFocusAfterHide();
+    }
+}
+
+WidgetFocusAfterHide.ATTRS = {
+    /**
+     * Whether to focus on the target that caused the Widget to be shown.
+     *
+     * <em>If this is true, and a valid Node is found, any Node specified to focusAfterHide
+     * will be ignored.</em>
+     *
+     * @attribute focusOnPreviousTargetAfterHide
+     * @default false
+     * @type boolean
+     */
+    focusOnPreviousTargetAfterHide: {
+        value: false
+    },
+
+    /**
+     * The Node to focus on after hiding the Widget.
+     *
+     * <em>Note: If focusOnPreviousTargetAfterHide is true, and a valid Node is found, then this
+     * value will be ignored. If it is true and not found, then this value will be used as
+     * a fallback.</em>
+     *
+     * @attribute focusAfterHide
+     * @default null
+     * @type Node
+     */
+    focusAfterHide: {
+        value: null,
+        type: Y.Node
+    }
+};
+
+WidgetFocusAfterHide.prototype = {
+    /**
+     * The list of Event Handles which we should cancel when the dialogue is destroyed.
+     *
+     * @property uiHandleFocusAfterHide
+     * @type array
+     * @protected
+     */
+    _uiHandlesFocusAfterHide: [],
+
+    /**
+     * A reference to the real show method which is being overwritten.
+     *
+     * @property _showFocusAfterHide
+     * @type function
+     * @default null
+     * @protected
+     */
+    _showFocusAfterHide: null,
+
+    /**
+     * A reference to the detected previous target.
+     *
+     * @property _previousTargetFocusAfterHide
+     * @type function
+     * @default null
+     * @protected
+     */
+    _previousTargetFocusAfterHide: null,
+
+    initializer: function() {
+
+        if (this.get('focusOnPreviousTargetAfterHide') && this.show) {
+            // Overwrite the parent method so that we can get the focused
+            // target.
+            this._showFocusAfterHide = this.show;
+            this.show = function(e) {
+                this._showFocusAfterHide.apply(this, arguments);
+
+                // We use a property rather than overriding the focusAfterHide parameter in
+                // case the target cannot be found at hide time.
+                this._previousTargetFocusAfterHide = null;
+                if (e && e.currentTarget) {
+                    Y.log("Determined a Node which caused the Widget to be shown",
+                            'debug', 'moodle-core-widget-focusafterhide');
+                    this._previousTargetFocusAfterHide = e.currentTarget;
+                }
+            };
+        }
+    },
+
+    destructor: function() {
+        new Y.EventHandle(this.uiHandleFocusAfterHide).detach();
+    },
+
+    /**
+     * Set up the event handling required for this module to work.
+     *
+     * @method _bindUIFocusAfterHide
+     * @private
+     */
+    _bindUIFocusAfterHide: function() {
+        // Detach the old handles first.
+        new Y.EventHandle(this.uiHandleFocusAfterHide).detach();
+        this.uiHandleFocusAfterHide = [
+            this.after('visibleChange', this._afterHostVisibleChangeFocusAfterHide)
+        ];
+    },
+
+    /**
+     * Handle the change in UI visibility.
+     *
+     * This method changes the focus after the hide has taken place.
+     *
+     * @method _afterHostVisibleChangeFocusAfterHide
+     * @private
+     */
+    _afterHostVisibleChangeFocusAfterHide: function() {
+        if (!this.get('visible')) {
+            if (this._attemptFocus(this._previousTargetFocusAfterHide)) {
+                Y.log("Focusing on the target automatically determined when the Widget was opened",
+                        'debug', 'moodle-core-widget-focusafterhide');
+
+            } else if (this._attemptFocus(this.get('focusAfterHide'))) {
+                // Fall back to the focusAfterHide value if one was specified.
+                Y.log("Focusing on the target provided to focusAfterHide",
+                        'debug', 'moodle-core-widget-focusafterhide');
+
+            } else {
+                Y.log("No valid focus target found - not returning focus.",
+                        'debug', 'moodle-core-widget-focusafterhide');
+
+            }
+        }
+    },
+
+    _attemptFocus: function(node) {
+        var focusTarget = Y.one(node);
+        if (focusTarget) {
+            focusTarget = focusTarget.ancestor(CAN_RECEIVE_FOCUS_SELECTOR, true);
+            if (focusTarget) {
+                focusTarget.focus();
+                return true;
+            }
+        }
+        return false;
+    }
+};
+
+var NS = Y.namespace('M.core');
+NS.WidgetFocusAfterHide = WidgetFocusAfterHide;
diff --git a/lib/yui/src/widget-focusafterclose/meta/notification.json b/lib/yui/src/widget-focusafterclose/meta/notification.json
new file mode 100644 (file)
index 0000000..0a836b2
--- /dev/null
@@ -0,0 +1,8 @@
+{
+    "moodle-core-widget-focusafterclose": {
+        "requires": [
+            "base-build",
+            "widget"
+        ]
+    }
+}
index cdbff35..20584a5 100644 (file)
@@ -189,7 +189,7 @@ class FPDF_TPL extends FPDF {
      * @param int $_y The y-position\r
      * @param int $_w The new width of the template\r
      * @param int $_h The new height of the template\r
-     * @retrun array The height and width of the template\r
+     * @return array The height and width of the template\r
      */\r
     function useTemplate($tplidx, $_x = null, $_y = null, $_w = 0, $_h = 0) {\r
         if ($this->page <= 0)\r
index 2d4104f..1ec80d4 100644 (file)
@@ -431,7 +431,7 @@ function forum_print_big_search_form($course) {
  *
  * @param string $words String containing space-separated strings to search for
  * @param string $prefix String to prepend to the each token taken out of $words
- * @returns array
+ * @return array
  * @todo Take the hardcoded limit out of this function and put it into a user-specified parameter
  */
 function forum_clean_search_terms($words, $prefix='') {
index 2a74c31..7014367 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Provides support for the conversion of moodle1 backup to the moodle2 format
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  2011 Andrew Davis <andrew@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index ccea8cd..38326ad 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Define all the backup steps that will be used by the backup_imscp_activity_task
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 16f861d..d4547b9 100644 (file)
@@ -16,7 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * @package moodlecore
+ * @package mod_imscp
  * @subpackage backup-moodle2
  * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index cfaf296..c1d278a 100644 (file)
@@ -16,7 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * @package moodlecore
+ * @package mod_imscp
  * @subpackage backup-moodle2
  * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
diff --git a/mod/imscp/classes/event/course_module_instance_list_viewed.php b/mod/imscp/classes/event/course_module_instance_list_viewed.php
new file mode 100644 (file)
index 0000000..e265a72
--- /dev/null
@@ -0,0 +1,31 @@
+<?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/>.
+
+/**
+ * The mod_imscp instance list viewed event.
+ *
+ * @package    mod_imscp
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_imscp\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+class course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed {
+    // No code required here as the parent class handles it all.
+}
diff --git a/mod/imscp/classes/event/course_module_viewed.php b/mod/imscp/classes/event/course_module_viewed.php
new file mode 100644 (file)
index 0000000..68fe5f6
--- /dev/null
@@ -0,0 +1,39 @@
+<?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/>.
+
+/**
+ * The mod_imscp course module viewed event.
+ *
+ * @package    mod_imscp
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_imscp\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+class course_module_viewed extends \core\event\course_module_viewed {
+
+    /**
+     * Init method.
+     */
+    protected function init() {
+        $this->data['objecttable'] = 'imscp';
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_PARTICIPATING;
+    }
+}
index a99e894..ec0df5b 100644 (file)
@@ -23,8 +23,7 @@
  *   - lib.php/modulename_install() post installation hook
  *   - partially defaults.php
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  2009 Petr Skoda  {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 1d90531..80e185d 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * IMS CP module upgrade code
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  2009 Petr Skoda  {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 469ce71..2b6ed50 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * List of file imscps in course
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  2009 onwards Martin Dougiamas (http://dougiamas.com)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -33,7 +32,11 @@ $course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST);
 require_course_login($course, true);
 $PAGE->set_pagelayout('incourse');
 
-add_to_log($course->id, 'imscp', 'view all', "index.php?id=$course->id", '');
+$params = array(
+    'context' => context_course::instance($course->id)
+);
+$event = \mod_imscp\event\course_module_instance_list_viewed::create($params);
+$event->trigger();
 
 $strimscp       = get_string('modulename', 'imscp');
 $strimscps      = get_string('modulenameplural', 'imscp');
index 6487200..c20ea67 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Strings for component 'imscp', language 'en', branch 'MOODLE_20_STABLE'
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index fb5f825..56bd522 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Mandatory public API of imscp module
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  2009 Petr Skoda  {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index b3dbafb..9a02dc1 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Private imscp module utility functions
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  2009 Petr Skoda  {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 06eeccc..417877c 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * IMS CP configuration form
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  2009 Petr Skoda  {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 8ae3ea9..eec0bdc 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * IMS CP module admin settings and defaults
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  2009 Petr Skoda  {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 7a2e2f3..d97ad7d 100644 (file)
@@ -17,8 +17,7 @@
 /**
  * IMS CP module version information
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  2009 Petr Skoda  {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index df749ab..6a11b58 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * IMS CP module main user interface
  *
- * @package    mod
- * @subpackage imscp
+ * @package mod_imscp
  * @copyright  2009 Petr Skoda  {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -46,7 +45,13 @@ require_course_login($course, true, $cm);
 $context = context_module::instance($cm->id);
 require_capability('mod/imscp:view', $context);
 
-add_to_log($course->id, 'imscp', 'view', 'view.php?id='.$cm->id, $imscp->id, $cm->id);
+$params = array(
+    'context' => $context,
+    'objectid' => $imscp->id
+);
+$event = \mod_imscp\event\course_module_viewed::create($params);
+$event->add_record_snapshot('imscp', $imscp);
+$event->trigger();
 
 // Update 'viewed' state if required by completion system
 $completion = new completion_info($course);
index dfd9634..dec832b 100644 (file)
@@ -19,8 +19,7 @@
  * Provides support for the conversion of moodle1 backup to the moodle2 format
  * Based off of a template @ http://docs.moodle.org/dev/Backup_1.9_conversion_for_developers
  *
- * @package    mod
- * @subpackage label
+ * @package mod_label
  * @copyright  2011 Aparup Banerjee <aparup@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 47fc4c7..486ad7d 100644 (file)
@@ -16,8 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * @package    mod
- * @subpackage label
+ * @package mod_label
  * @copyright  2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 6bfad23..8b37d24 100644 (file)
@@ -16,7 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * @package moodlecore
+ * @package mod_label
  * @subpackage backup-moodle2
  * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index c590499..b08698d 100644 (file)
@@ -16,7 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * @package moodlecore
+ * @package mod_label
  * @subpackage backup-moodle2
  * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 66406af..00adcbb 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Label module upgrade
  *
- * @package    mod
- * @subpackage label
+ * @package mod_label
  * @copyright  2006 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index f13776a..47df577 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Library of functions and constants for module label
  *
- * @package    mod
- * @subpackage label
+ * @package mod_label
  * @copyright  2003 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 5731413..8089696 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Strings for component 'label', language 'en', branch 'MOODLE_20_STABLE'
  *
- * @package    mod
- * @subpackage label
+ * @package mod_label
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index a9aea19..afac5f3 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Library of functions and constants for module label
  *
- * @package    mod
- * @subpackage label
+ * @package mod_label
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index ad86a4c..a9b436a 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Add label form
  *
- * @package    mod
- * @subpackage label
+ * @package mod_label
  * @copyright  2006 Jamie Pratt
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 5418fb5..c4f3ae8 100644 (file)
@@ -17,8 +17,7 @@
 /**
  * Label module version info
  *
- * @package    mod
- * @subpackage label
+ * @package mod_label
  * @copyright  2003 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index b9e88a5..b00cd6c 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Label module
  *
- * @package    mod
- * @subpackage label
+ * @package mod_label
  * @copyright  2003 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index e6e5d1d..5a9b0d2 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Provides support for the conversion of moodle1 backup to the moodle2 format
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2011 Rossiani Wijaya <rwijaya@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index fa880a0..30367de 100644 (file)
@@ -49,8 +49,7 @@
  *          UL->user level info
  *          files->table may have files)
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2010 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 3f44d84..4b8351c 100644 (file)
@@ -16,7 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * @package moodlecore
+ * @package mod_lesson
  * @subpackage backup-moodle2
  * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 8907e74..a06adb5 100644 (file)
@@ -16,7 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * @package moodlecore
+ * @package mod_lesson
  * @subpackage backup-moodle2
  * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 79f3499..9144edc 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Action for processing page answers by users
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index ceb444f..1e2f3c8 100644 (file)
@@ -18,7 +18,7 @@
 /**
  * Defines message providers (types of messages being sent)
  *
- * @package mod-lesson
+ * @package mod_lesson
  * @copyright 2010 Andrew Davis
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 149376f..5a235a7 100644 (file)
@@ -36,8 +36,7 @@
  * Please do not forget to use upgrade_set_timeout()
  * before any action that may take longer time to finish.
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 o
  */
index aeeb201..2bcae9e 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Provides the interface for overall authoring of lessons
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 140de2e..e61107c 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Action for adding a question page.  Prints an HTML form.
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 94064d1..f4fa4dc 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Generic forms used for page selection
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 44e972b..3026e20 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Provides the interface for grading essay questions
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index ce2df3b..883c4e6 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Essay grading form
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 1411525..e4916d6 100644 (file)
@@ -21,8 +21,7 @@
  *
  * Included by import.ph
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 0493cd7..d1c3596 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Provides the interface for viewing and adding high scores
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 24e6fe5..a3d2281 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Imports lesson pages
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 765d565..b152c0a 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Form used to select a file and file format for the import
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index ad13f61..ad143e4 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * This page lists all the instances of lesson in a particular course
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 971381d..dcfb162 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Strings for component 'lesson', language 'en', branch 'MOODLE_20_STABLE'
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index d082b5e..fb4314f 100644 (file)
@@ -23,8 +23,7 @@
  *    delete
  *    move
  *    moveit
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 10ff1d6..ba948ac 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Standard library of functions and constants for lesson
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 070e2e9..0eb7e06 100644 (file)
@@ -19,8 +19,7 @@
  * Local library file for Lesson.  These are non-standard functions that are used
  * only by Lesson.
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
  **/
index 7ad10af..71240f9 100644 (file)
@@ -21,8 +21,7 @@
  *  If there is a way to use the resource class instead of this code, please change to do so
  *
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index e4c3566..431f5ef 100644 (file)
@@ -19,8 +19,7 @@
  * Form to define a new instance of lesson or edit an instance.
  * It is used from /course/modedit.php.
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
  **/
index d636271..749f85d 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Branch Table
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 9351db6..c179913 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Cluster
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index ed40281..fdbfc3e 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * End of branch table
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index b552e0a..fb8914d 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * End of cluster
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 3fc1ac7..be86f7a 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Essay
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index dc83ac5..ea0f0f4 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Matching
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index aaf762d..81d45da 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Multichoice
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 0240b77..0285965 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Numerical
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index f504bd3..9d5cbd1 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Short answer
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index aa62764..7a8a0f4 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * True/false
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index 7712341..2997302 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * jjg7:8/9/2004
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
  **/
index ac87ac4..2db18b6 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Moodle renderer used to display special elements of the lesson module
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index e4ef0d5..41e03d9 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Displays the lesson statistics.
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
  **/
index 2b3fdb2..cd909a6 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Settings used by the lesson module, were moved from mod_edit
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
  **/
index 548ad18..f804279 100644 (file)
@@ -20,8 +20,7 @@
 *
 * This file was adapted from the mod/quiz/tabs.php
 *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
 */
index cc87aed..159ed34 100644 (file)
@@ -17,8 +17,7 @@
 /**
  * Version information
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 383e9f9..1e28ab6 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * This page prints a particular instance of lesson
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
  **/
index f7c108a..db30a3b 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Lesson page without answers
  *
- * @package    mod
- * @subpackage lesson
+ * @package mod_lesson
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  **/
index afe686c..73c3ad5 100644 (file)
@@ -50,7 +50,7 @@
 /**
  * This file contains a Trivial memory-based store - no support for tokens
  *
- * @package lti
+ * @package mod_lti
  * @copyright IMS Global Learning Consortium
  *
  * @author Charles Severance csev@umich.edu
index b798f46..75b638d 100644 (file)
@@ -17,8 +17,7 @@
 /**
  * 1.9 to 2.0 backup format converter. (Also currently used in common cartridge import process)
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  * @author     Darko Miletic
index 2c0b038..8a7ac39 100644 (file)
@@ -36,8 +36,7 @@
  * This file contains all the backup steps that will be used
  * by the backup_lti_activity_task
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index 773fe2d..61113e0 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file contains the lti module restore class
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index 2a76b52..042ac9f 100644 (file)
@@ -36,8 +36,7 @@
  * This file contains all the restore steps that will be used
  * by the restore_lti_activity_task
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index f51f82e..2435b9c 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file keeps track of upgrades to the lti module
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index cdc801b..558c1b4 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file defines de main basiclti configuration form
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index eace2ca..c3c063d 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file contains submissions-specific code for the lti module
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index 65b9ad7..9e931f0 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This page lists all the instances of lti in a particular course
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index 3a70051..2a2cefb 100644 (file)
@@ -17,8 +17,7 @@
 /**
  * This page allows instructors to configure course level tool providers.
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  * @author     Chris Scribner
index af2b969..da8bf22 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file contains en_utf8 translation of the Basic LTI module
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index de31c7a..67e88ab 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file contains all necessary code to view a lti activity instance
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index 895532a..0e761e1 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file contains a library of functions and constants for the lti module
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index 7aee7db..1ccb424 100644 (file)
@@ -36,8 +36,7 @@
  * This file contains some functions and classes used by the lti
  * module administration
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index f0fdcf6..4397d3b 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file contains the library of functions and constants for the lti module
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index fe517ae..67b1cfc 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file defines the main lti configuration form
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index ed3bb2e..d929e73 100644 (file)
@@ -17,8 +17,7 @@
 /**
  * Submits a request to administrators to add a tool configuration for the requested site.
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  * @author     Chris Scribner
index b0940bb..d4f1980 100644 (file)
@@ -17,8 +17,7 @@
 /**
  * Handle the return back to Moodle from the tool provider
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  * @author     Chris Scribner
index 3150bbb..cdf3148 100644 (file)
@@ -17,8 +17,7 @@
 /**
  * LTI web service endpoints
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  * @author     Chris Scribner
index 3a5dcf3..3d7cc0e 100644 (file)
@@ -17,8 +17,7 @@
 /**
  * Utility code for LTI service handling.
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  * @author     Chris Scribner
index 46e5bb0..ad75437 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file defines the global lti administration form
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index d9c8d9b..ab5895a 100644 (file)
@@ -36,8 +36,7 @@
  * This file contains the script used to clone Moodle admin setting page.
  * It is used to create a new form used to pre-configure lti activities
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index 479538a..fc8079d 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file defines the version of lti
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index b4a80d9..d61632e 100644 (file)
@@ -35,8 +35,7 @@
 /**
  * This file contains all necessary code to view a lti activity instance
  *
- * @package    mod
- * @subpackage lti
+ * @package mod_lti
  * @copyright  2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  *  marc.alier@upc.edu
  * @copyright  2009 Universitat Politecnica de Catalunya http://www.upc.edu
index 51b8a2f..f1e4bc3 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Provides support for the conversion of moodle1 backup to the moodle2 format
  *
- * @package    mod
- * @subpackage page
+ * @package mod_page
  * @copyright  2011 Andrew Davis <andrew@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 56576bd..ea47381 100644 (file)
@@ -16,8 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * @package    mod
- * @subpackage page
+ * @package mod_page
  * @copyright  2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 2951bb5..e8ef893 100644 (file)
@@ -16,7 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * @package moodlecore
+ * @package mod_page
  * @subpackage backup-moodle2
  * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 862b07d..c6562a1 100644 (file)
@@ -16,7 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * @package moodlecore
+ * @package mod_page
  * @subpackage backup-moodle2
  * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 0714948..e113d11 100644 (file)
@@ -23,8 +23,7 @@
  *  - lib.php/modulename_install() post installation hook
  *  - partially defaults.php
  *
- * @package    mod
- * @subpackage page
+ * @package mod_page
  * @copyright  2009 Petr Skoda (http://skodak.org)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 1a5fb50..0e26264 100644 (file)
@@ -38,8 +38,7 @@
  * Please do not forget to use upgrade_set_timeout()
  * before any action that may take longer time to finish.
  *
- * @package    mod
- * @subpackage page
+ * @package mod_page
  * @copyright  2009 Petr Skoda (http://skodak.org)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index eb2676a..08906b8 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * List of all pages in course
  *
- * @package    mod
- * @subpackage page
+ * @package mod_page
  * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 605f664..5a3210c 100644 (file)
@@ -18,7 +18,7 @@
 /**
  * Strings for component 'page', language 'en', branch 'MOODLE_20_STABLE'
  *
- * @package   page
+ * @package   mod_page
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index b4a649f..c9ce161 100644 (file)
@@ -16,8 +16,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * @package    mod
- * @subpackage page
+ * @package mod_page
  * @copyright  2009 Petr Skoda (http://skodak.org)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 5eb4d0f..1079b4e 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Private page module utility functions
  *
- * @package    mod
- * @subpackage page
+ * @package mod_page
  * @copyright  2009 Petr Skoda (http://skodak.org)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index d982d7a..69e51ea 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Page configuration form
  *
- * @package    mod
- * @subpackage page
+ * @package mod_page
  * @copyright  2009 Petr Skoda (http://skodak.org)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index b622d35..59fcc6b 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Page module admin settings and defaults
  *
- * @package    mod
- * @subpackage page
+ * @package mod_page
  * @copyright  2009 Petr Skoda (http://skodak.org)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 740da1b..6185873 100644 (file)
@@ -17,8 +17,7 @@
 /**
  * Page module version information
  *
- * @package    mod
- * @subpackage page
+ * @package mod_page
  * @copyright  2009 Petr Skoda (http://skodak.org)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 5abe1d3..25431d2 100644 (file)
@@ -18,8 +18,7 @@
 /**
  * Page module version information
  *
- * @package    mod
- * @subpackage page
+ * @package mod_page
  * @copyright  2009 Petr Skoda (http://skodak.org)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index b29ae77..60ab922 100644 (file)
@@ -380,6 +380,16 @@ function quiz_has_grades($quiz) {
     return $quiz->grade >= 0.000005 && $quiz->sumgrades >= 0.000005;
 }
 
+/**
+ * Does this quiz allow multiple tries?
+ *
+ * @return bool
+ */
+function quiz_allows_multiple_tries($quiz) {
+    $bt = question_engine::get_behaviour_type($quiz->preferredbehaviour);
+    return $bt->allows_multiple_submitted_responses();
+}
+
 /**
  * Return a small object with summary information about what a
  * user has done with a given particular instance of this module
index 28a6d82..61f3247 100644 (file)
@@ -234,25 +234,26 @@ abstract class quiz_attempts_report_table extends table_sql {
     public function make_review_link($data, $attempt, $slot) {
         global $OUTPUT;
 
-        $stepdata = $this->lateststeps[$attempt->usageid][$slot];
-        $state = question_state::get($stepdata->state);
-
         $flag = '';
-        if ($stepdata->flagged) {
+        if ($this->is_flagged($attempt->usageid, $slot)) {
             $flag = $OUTPUT->pix_icon('i/flagged', get_string('flagged', 'question'),
                     'moodle', array('class' => 'questionflag'));
         }
 
         $feedbackimg = '';
+        $state = $this->slot_state($attempt, $slot);
         if ($state->is_finished() && $state != question_state::$needsgrading) {
-            $feedbackimg = $this->icon_for_fraction($stepdata->fraction);
+            $feedbackimg = $this->icon_for_fraction($this->slot_fraction($attempt, $slot));
         }
 
         $output = html_writer::tag('span', $feedbackimg . html_writer::tag('span',
                 $data, array('class' => $state->get_state_class(true))) . $flag, array('class' => 'que'));
 
-        $url = new moodle_url('/mod/quiz/reviewquestion.php',
-                array('attempt' => $attempt->attempt, 'slot' => $slot));
+        $reviewparams = array('attempt' => $attempt->attempt, 'slot' => $slot);
+        if (isset($attempt->try)) {
+            $reviewparams['step'] = $this->step_no_for_try($attempt->usageid, $slot, $attempt->try);
+        }
+        $url = new moodle_url('/mod/quiz/reviewquestion.php', $reviewparams);
         $output = $OUTPUT->action_link($url, $output,
                 new popup_action('click', $url, 'reviewquestion',
                         array('height' => 450, 'width' => 650)),
@@ -261,6 +262,37 @@ abstract class quiz_attempts_report_table extends table_sql {
         return $output;
     }
 
+    /**
+     * @param object $attempt the row data
+     * @param int $slot
+     * @return question_state
+     */
+    protected function slot_state($attempt, $slot) {
+        $stepdata = $this->lateststeps[$attempt->usageid][$slot];
+        return question_state::get($stepdata->state);
+    }
+
+    /**
+     * @param int $questionusageid
+     * @param int $slot
+     * @return bool
+     */
+    protected function is_flagged($questionusageid, $slot) {
+        $stepdata = $this->lateststeps[$questionusageid][$slot];
+        return $stepdata->flagged;
+    }
+
+
+    /**
+     * @param object $attempt the row data
+     * @param int $slot
+     * @return float
+     */
+    protected function slot_fraction($attempt, $slot) {
+        $stepdata = $this->lateststeps[$attempt->usageid][$slot];
+        return $stepdata->fraction;
+    }
+
     /**
      * Return an appropriate icon (green tick, red cross, etc.) for a grade.
      * @param float $fraction grade on a scale 0..1.
@@ -274,16 +306,28 @@ abstract class quiz_attempts_report_table extends table_sql {
                 'moodle', array('class' => 'icon'));
     }
 
+    /**
+     * Load any extra data after main query. At this point you can call {@link get_qubaids_condition} to get the condition that
+     * limits the query to just the question usages shown in this report page or alternatively for all attempts if downloading a
+     * full report.
+     */
+    protected function load_extra_data() {
+        $this->lateststeps = $this->load_question_latest_steps();
+    }
+
     /**
      * Load information about the latest state of selected questions in selected attempts.
      *
      * The results are returned as an two dimensional array $qubaid => $slot => $dataobject
      *
-     * @param qubaid_condition $qubaids used to restrict which usages are included
+     * @param qubaid_condition|null $qubaids used to restrict which usages are included
      * in the query. See {@link qubaid_condition}.
      * @return array of records. See the SQL in this function to see the fields available.
      */
-    protected function load_question_latest_steps(qubaid_condition $qubaids) {
+    protected function load_question_latest_steps(qubaid_condition $qubaids = null) {
+        if ($qubaids === null) {
+            $qubaids = $this->get_qubaids_condition();
+        }
         $dm = new question_engine_data_mapper();
         $latesstepdata = $dm->load_questions_usages_latest_steps(
                 $qubaids, array_keys($this->questions));
@@ -296,10 +340,20 @@ abstract class quiz_attempts_report_table extends table_sql {
         return $lateststeps;
     }
 
+    /**
+     * Does this report require loading any more data after the main query. After the main query then
+     * you can use $this->get
+     *
+     * @return bool should {@link query_db()} call {@link load_extra_data}?
+     */
+    protected function requires_extra_data() {
+        return $this->requires_latest_steps_loaded();
+    }
+
     /**
      * Does this report require the detailed information for each question from the
      * question_attempts_steps table?
-     * @return bool should {@link query_db()} call {@link load_question_latest_steps}?
+     * @return bool should {@link load_extra_data} call {@link load_question_latest_steps}?
      */
     protected function requires_latest_steps_loaded() {
         return false;
@@ -486,9 +540,8 @@ abstract class quiz_attempts_report_table extends table_sql {
 
         parent::query_db($pagesize, $useinitialsbar);
 
-        if ($this->requires_latest_steps_loaded()) {
-            $qubaids = $this->get_qubaids_condition();
-            $this->lateststeps = $this->load_question_latest_steps($qubaids);
+        if ($this->requires_extra_data()) {
+            $this->load_extra_data();
         }
     }
 
diff --git a/mod/quiz/report/responses/first_or_all_responses_table.php b/mod/quiz/report/responses/first_or_all_responses_table.php
new file mode 100644 (file)
index 0000000..fced6f0
--- /dev/null
@@ -0,0 +1,245 @@
+<?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/>.
+
+/**
+ * This file defines the quiz responses table for showing first or all tries at a question.
+ *
+ * @package   quiz_responses
+ * @copyright 2014 The Open University
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * This is a table subclass for displaying the quiz responses report, showing first or all tries.
+ *
+ * @copyright 2008 Jean-Michel Vedrine
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class quiz_first_or_all_responses_table extends quiz_last_responses_table {
+
+    /**
+     * The full question usage object for each attempt shown in report.
+     *
+     * @var question_usage_by_activity[]
+     */
+    protected $questionusagesbyactivity;
+
+    protected function field_from_extra_data($attempt, $slot, $field) {
+        $questionattempt = $this->get_question_attempt($attempt->usageid, $slot);
+        switch($field) {
+            case 'questionsummary' :
+                return $questionattempt->get_question_summary();
+            case 'responsesummary' :
+                return $this->get_summary_after_try($attempt, $slot);
+            case 'rightanswer' :
+                return $questionattempt->get_right_answer_summary();
+            default :
+                throw new coding_exception('Unknown question attempt field.');
+        }
+    }
+
+
+    protected function load_extra_data() {
+        $qubaids = $this->get_qubaids_condition();
+        $dm = new question_engine_data_mapper();
+        $this->questionusagesbyactivity = $dm->load_questions_usages_by_activity($qubaids);
+
+        // Insert an extra field in attempt data and extra rows where necessary.
+        $newrawdata = array();
+        foreach ($this->rawdata as $attempt) {
+            $maxtriesinanyslot = 1;
+            foreach ($this->questionusagesbyactivity[$attempt->usageid]->get_slots() as $slot) {
+                $tries = $this->get_no_of_tries($attempt, $slot);
+                $maxtriesinanyslot = max($maxtriesinanyslot, $tries);
+            }
+            for ($try = 1; $try <= $maxtriesinanyslot; $try++) {
+                $newattemptrow = clone($attempt);
+                $newattemptrow->lasttryforallparts = ($try == $maxtriesinanyslot);
+                if ($try !== $maxtriesinanyslot) {
+                    $newattemptrow->state = quiz_attempt::IN_PROGRESS;
+                }
+                $newattemptrow->try = $try;
+                $newrawdata[] = $newattemptrow;
+                if ($this->options->whichtries == question_attempt::FIRST_TRY) {
+                    break;
+                }
+            }
+        }
+        $this->rawdata = $newrawdata;
+    }
+
+    /**
+     * Return the question attempt object.
+     *
+     * @param int $questionusagesid
+     * @param int $slot
+     * @return question_attempt
+     */
+    protected function get_question_attempt($questionusagesid, $slot) {
+        return $this->questionusagesbyactivity[$questionusagesid]->get_question_attempt($slot);
+    }
+
+    /**
+     * @param object $attempt row data
+     * @param int $slot
+     * @return question_state
+     */
+    protected function slot_state($attempt, $slot) {
+        $qa = $this->get_question_attempt($attempt->usageid, $slot);
+        $submissionsteps = $qa->get_steps_with_submitted_response_iterator();
+        $step = $submissionsteps[$attempt->try];
+        if ($step === null) {
+            return null;
+        }
+        if ($this->is_last_try($attempt, $slot, $attempt->try)) {
+            // If this is the last try then the step with the try data does not contain the correct state. We need to
+            // use the last step's state, after the attempt has been finished.
+            return $qa->get_state();
+        }
+        return $step->get_state();
+    }
+
+
+    /**
+     * @param object $attempt row data
+     * @param int $slot
+     * @return string summary for the question after this try.
+     */
+    public function get_summary_after_try($attempt, $slot) {
+        $qa = $this->get_question_attempt($attempt->usageid, $slot);
+        $submissionsteps = $qa->get_steps_with_submitted_response_iterator();
+        $step = $submissionsteps[$attempt->try];
+        if ($step === null) {
+            return null;
+        }
+        $qtdata = $step->get_qt_data();
+        return $qa->get_question()->summarise_response($qtdata);
+    }
+
+    /**
+     * @param int $questionusageid
+     * @param int $slot
+     * @return bool
+     */
+    protected function is_flagged($questionusageid, $slot) {
+        return $this->get_question_attempt($questionusageid, $slot)->is_flagged();
+    }
+
+    /**
+     * @param object $attempt attempt data from db.
+     * @param int $slot
+     * @return float
+     */
+    protected function slot_fraction($attempt, $slot) {
+        $qa = $this->get_question_attempt($attempt->usageid, $slot);
+        $submissionsteps = $qa->get_steps_with_submitted_response_iterator();
+        $step = $submissionsteps[$attempt->try];
+        if ($step === null) {
+            return null;
+        }
+        if ($this->is_last_try($attempt, $slot, $attempt->try)) {
+            // If this is the last try then the step with the try data does not contain the correct fraction. We need to
+            // use the last step's fraction, after the attempt has been finished.
+            return $qa->get_fraction();
+        }
+        return $step->get_fraction();
+    }
+
+    /**
+     * Is this the last try in the question attempt?
+     *
+     * @param object $attempt attempt data from db.
+     * @param int $slot
+     * @param int $tryno try no
+     * @return bool
+     */
+    protected function is_last_try($attempt, $slot, $tryno) {
+        return $tryno == $this->get_no_of_tries($attempt, $slot);
+    }
+
+    /**
+     * @param object $attempt attempt data from db.
+     * @param int $slot
+     * @return int the number of tries in the question attempt for slot $slot.
+     */
+    public function get_no_of_tries($attempt, $slot) {
+        return count($this->get_question_attempt($attempt->usageid, $slot)->get_steps_with_submitted_response_iterator());
+    }
+
+
+    /**
+     * @param int $questionusageid
+     * @param int $slot
+     * @param int $tryno
+     * @return int the step no or zero if not found
+     */
+    protected function step_no_for_try($questionusageid, $slot, $tryno) {
+        return $this->get_question_attempt($questionusageid, $slot)->get_steps_with_submitted_response_iterator()->step_no_for_try($tryno);
+    }
+
+    public function col_checkbox($attempt) {
+        if ($attempt->try != 1) {
+            return '';
+        } else {
+            return parent::col_checkbox($attempt);
+        }
+    }
+
+    public function col_email($attempt) {
+        if ($attempt->try != 1) {
+            return '';
+        } else {
+            return $attempt->email;
+        }
+    }
+
+    public function col_sumgrades($attempt) {
+        if (!$attempt->lasttryforallparts) {
+            return '';
+        } else {
+            return parent::col_sumgrades($attempt);
+        }
+    }
+
+
+    public function col_state($attempt) {
+        if (!$attempt->lasttryforallparts) {
+            return '';
+        } else {
+            return parent::col_state($attempt);
+        }
+    }
+
+    public function get_row_class($attempt) {
+        if ($this->options->whichtries == question_attempt::ALL_TRIES && $attempt->lasttryforallparts) {
+            return 'lastrowforattempt';
+        } else {
+            return '';
+        }
+    }
+
+    public function make_review_link($data, $attempt, $slot) {
+        if ($this->slot_state($attempt, $slot) === null) {
+            return $data;
+        } else {
+            return parent::make_review_link($data, $attempt, $slot);
+        }
+    }
+}
+
+