Merge branch 'MDL40479_Grading_alert_colour' of https://github.com/Dave-B/moodle
authorSam Hemelryk <sam@moodle.com>
Sun, 20 Jul 2014 23:32:09 +0000 (11:32 +1200)
committerSam Hemelryk <sam@moodle.com>
Sun, 20 Jul 2014 23:32:09 +0000 (11:32 +1200)
103 files changed:
admin/settings/users.php
admin/tool/behat/tests/behat/manipulate_forms.feature
admin/tool/uploaduser/user_form.php
auth/cas/auth.php
badges/edit_form.php
blog/edit.php
blog/edit_form.php
blog/external_blog_edit.php
blog/external_blog_edit_form.php
blog/external_blogs.php
blog/index.php
blog/lib.php
blog/locallib.php
blog/preferences.php
blog/preferences_form.php
blog/renderer.php
blog/rsslib.php
blog/tests/bloglib_test.php
calendar/event_form.php
calendar/lib.php
calendar/tests/lib_test.php
course/classes/management_renderer.php
course/management.php
enrol/imsenterprise/lib.php
files/renderer.php
filter/activitynames/filter.php
group/autogroup.php
group/autogroup_form.php
group/lib.php
group/tests/behat/auto_creation.feature
install/lang/af/moodle.php [new file with mode: 0644]
install/lang/ru/install.php
lang/en/admin.php
lang/en/group.php
lang/en/moodle.php
lib/authlib.php
lib/classes/event/recent_activity_viewed.php
lib/classes/task/adhoc_task.php
lib/classes/task/manager.php
lib/completionlib.php
lib/form/filemanager.js
lib/htmlpurifier/locallib.php
lib/moodlelib.php
lib/testing/generator/data_generator.php
lib/tests/htmlpurifier_test.php
lib/upgrade.txt
lib/weblib.php
login/index.php
login/index_form.html
message/lib.php
mod/assign/gradingtable.php
mod/assign/lang/en/assign.php
mod/assign/renderer.php
mod/assign/tests/locallib_test.php
mod/feedback/item/textarea/lib.php
mod/feedback/item/textfield/lib.php
mod/forum/classes/event/user_report_viewed.php
mod/forum/lib.php
mod/quiz/backup/moodle2/backup_quiz_stepslib.php
mod/quiz/db/install.xml
mod/quiz/db/upgrade.php
mod/quiz/lang/en/quiz.php
mod/quiz/lib.php
mod/quiz/locallib.php
mod/quiz/mod_form.php
mod/quiz/tests/behat/completion_condition_attempts_used.feature [new file with mode: 0644]
mod/quiz/tests/behat/completion_condition_passing_grade.feature [new file with mode: 0644]
mod/quiz/version.php
mod/scorm/datamodels/aicc.js [moved from mod/scorm/datamodels/aicc.js.php with 81% similarity]
mod/scorm/datamodels/aicc.php [new file with mode: 0644]
mod/scorm/datamodels/aicclib.php
mod/scorm/datamodels/debug.js.php
mod/scorm/datamodels/scorm_12.js [moved from mod/scorm/datamodels/scorm_12.js.php with 75% similarity]
mod/scorm/datamodels/scorm_12.php [new file with mode: 0644]
mod/scorm/datamodels/scorm_12lib.php
mod/scorm/datamodels/scorm_13.js [moved from mod/scorm/datamodels/scorm_13.js.php with 87% similarity]
mod/scorm/datamodels/scorm_13.php [new file with mode: 0644]
mod/scorm/datamodels/scorm_13lib.php
mod/scorm/loaddatamodel.php [deleted file]
mod/scorm/locallib.php
mod/scorm/module.js
mod/scorm/player.php
mod/scorm/version.php
mod/scorm/view.php
mod/survey/classes/event/report_downloaded.php
mod/survey/classes/event/report_viewed.php
mod/wiki/pagelib.php
mod/wiki/tests/behat/wiki_comments.feature [new file with mode: 0644]
notes/delete.php
notes/edit.php
report/eventlist/tests/behat/mainsection.feature
report/outline/classes/event/activity_report_viewed.php
report/outline/classes/event/report_viewed.php
repository/filepicker.js
theme/base/style/core.css
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/less/moodle/filemanager.less
theme/bootstrapbase/style/moodle.css
user/editlib.php
user/lib.php
user/profile.php
user/view.php
version.php

index 2231bab..5a7e75a 100644 (file)
@@ -24,6 +24,46 @@ if ($hassiteconfig
     $ADMIN->add('accounts', new admin_externalpage('editusers', new lang_string('userlist','admin'), "$CFG->wwwroot/$CFG->admin/user.php", array('moodle/user:update', 'moodle/user:delete')));
     $ADMIN->add('accounts', new admin_externalpage('userbulk', new lang_string('userbulk','admin'), "$CFG->wwwroot/$CFG->admin/user/user_bulk.php", array('moodle/user:update', 'moodle/user:delete')));
     $ADMIN->add('accounts', new admin_externalpage('addnewuser', new lang_string('addnewuser'), "$securewwwroot/user/editadvanced.php?id=-1", 'moodle/user:create'));
+
+    // "User default preferences" settingpage.
+    $temp = new admin_settingpage('userdefaultpreferences', new lang_string('userdefaultpreferences', 'admin'));
+    if ($ADMIN->fulltree) {
+        $choices = array();
+        $choices['0'] = new lang_string('emaildisplayno');
+        $choices['1'] = new lang_string('emaildisplayyes');
+        $choices['2'] = new lang_string('emaildisplaycourse');
+        $temp->add(new admin_setting_configselect('defaultpreference_maildisplay', new lang_string('emaildisplay'),
+            '', 2, $choices));
+
+        $choices = array();
+        $choices['0'] = new lang_string('textformat');
+        $choices['1'] = new lang_string('htmlformat');
+        $temp->add(new admin_setting_configselect('defaultpreference_mailformat', new lang_string('emailformat'), '', 1, $choices));
+
+        $choices = array();
+        $choices['0'] = new lang_string('emaildigestoff');
+        $choices['1'] = new lang_string('emaildigestcomplete');
+        $choices['2'] = new lang_string('emaildigestsubjects');
+        $temp->add(new admin_setting_configselect('defaultpreference_maildigest', new lang_string('emaildigest'),
+            new lang_string('emaildigest_help'), 0, $choices));
+
+
+        $choices = array();
+        $choices['1'] = new lang_string('autosubscribeyes');
+        $choices['0'] = new lang_string('autosubscribeno');
+        $temp->add(new admin_setting_configselect('defaultpreference_autosubscribe', new lang_string('autosubscribe'),
+            '', 1, $choices));
+
+        if (!empty($CFG->forum_trackreadposts)) {
+            $choices = array();
+            $choices['0'] = new lang_string('trackforumsno');
+            $choices['1'] = new lang_string('trackforumsyes');
+            $temp->add(new admin_setting_configselect('defaultpreference_trackforums', new lang_string('trackforums'),
+                '', 0, $choices));
+        }
+    }
+    $ADMIN->add('accounts', $temp);
+
     $ADMIN->add('accounts', new admin_externalpage('profilefields', new lang_string('profilefields','admin'), "$CFG->wwwroot/user/profile/index.php", 'moodle/site:config'));
     $ADMIN->add('accounts', new admin_externalpage('cohorts', new lang_string('cohorts', 'cohort'), $CFG->wwwroot . '/cohort/index.php', array('moodle/cohort:manage', 'moodle/cohort:view')));
 
index 3696b81..952b65a 100644 (file)
@@ -11,6 +11,7 @@ Feature: Forms manipulation
     When I set the field "First name" to "Field value"
     And I set the field "Text editor" to "Plain text area"
     And I set the field "Unmask" to "1"
+    And I expand all fieldsets
     Then the field "First name" matches value "Field value"
     And the "Text editor" select box should contain "Plain text area"
     And the field "Unmask" matches value "1"
index f922995..1ec16e0 100644 (file)
@@ -221,21 +221,21 @@ class admin_uploaduser_form2 extends moodleform {
 
         $choices = array(0 => get_string('emaildisplayno'), 1 => get_string('emaildisplayyes'), 2 => get_string('emaildisplaycourse'));
         $mform->addElement('select', 'maildisplay', get_string('emaildisplay'), $choices);
-        $mform->setDefault('maildisplay', 2);
+        $mform->setDefault('maildisplay', $CFG->defaultpreference_maildisplay);
 
         $choices = array(0 => get_string('textformat'), 1 => get_string('htmlformat'));
         $mform->addElement('select', 'mailformat', get_string('emailformat'), $choices);
-        $mform->setDefault('mailformat', 1);
+        $mform->setDefault('mailformat', $CFG->defaultpreference_mailformat);
         $mform->setAdvanced('mailformat');
 
         $choices = array(0 => get_string('emaildigestoff'), 1 => get_string('emaildigestcomplete'), 2 => get_string('emaildigestsubjects'));
         $mform->addElement('select', 'maildigest', get_string('emaildigest'), $choices);
-        $mform->setDefault('maildigest', 0);
+        $mform->setDefault('maildigest', $CFG->defaultpreference_maildigest);
         $mform->setAdvanced('maildigest');
 
         $choices = array(1 => get_string('autosubscribeyes'), 0 => get_string('autosubscribeno'));
         $mform->addElement('select', 'autosubscribe', get_string('autosubscribe'), $choices);
-        $mform->setDefault('autosubscribe', 1);
+        $mform->setDefault('autosubscribe', $CFG->defaultpreference_autosubscribe);
 
         $mform->addElement('text', 'city', get_string('city'), 'maxlength="120" size="25"');
         $mform->setType('city', PARAM_TEXT);
index 6615b75..9d83dd1 100644 (file)
@@ -111,6 +111,26 @@ class auth_plugin_cas extends auth_plugin_ldap {
             return;
         }
 
+        // If the multi-authentication setting is used, check for the param before connecting to CAS.
+        if ($this->config->multiauth) {
+            $authCAS = optional_param('authCAS', '', PARAM_RAW);
+            if ($authCAS == 'NOCAS') {
+                return;
+            }
+            // Show authentication form for multi-authentication.
+            // Test pgtIou parameter for proxy mode (https connection in background from CAS server to the php server).
+            if ($authCAS != 'CAS' && !isset($_GET['pgtIou'])) {
+                $PAGE->set_url('/login/index.php');
+                $PAGE->navbar->add($CASform);
+                $PAGE->set_title("$site->fullname: $CASform");
+                $PAGE->set_heading($site->fullname);
+                echo $OUTPUT->header();
+                include($CFG->dirroot.'/auth/cas/cas_form.html');
+                echo $OUTPUT->footer();
+                exit();
+            }
+        }
+
         // Connection to CAS server
         $this->connectCAS();
 
@@ -134,27 +154,6 @@ class auth_plugin_cas extends auth_plugin_ldap {
             return;
         }
 
-        if ($this->config->multiauth) {
-            $authCAS = optional_param('authCAS', '', PARAM_RAW);
-            if ($authCAS == 'NOCAS') {
-                return;
-            }
-
-            // Show authentication form for multi-authentication
-            // test pgtIou parameter for proxy mode (https connection
-            // in background from CAS server to the php server)
-            if ($authCAS != 'CAS' && !isset($_GET['pgtIou'])) {
-                $PAGE->set_url('/login/index.php');
-                $PAGE->navbar->add($CASform);
-                $PAGE->set_title("$site->fullname: $CASform");
-                $PAGE->set_heading($site->fullname);
-                echo $OUTPUT->header();
-                include($CFG->dirroot.'/auth/cas/cas_form.html');
-                echo $OUTPUT->footer();
-                exit();
-            }
-        }
-
         // Force CAS authentication (if needed).
         if (!phpCAS::isAuthenticated()) {
             phpCAS::setLang($this->config->language);
index 24e52d7..cebc483 100644 (file)
@@ -54,7 +54,7 @@ class edit_details_form extends moodleform {
         $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         $mform->addElement('textarea', 'description', get_string('description', 'badges'), 'wrap="virtual" rows="8" cols="70"');
-        $mform->setType('description', PARAM_CLEANHTML);
+        $mform->setType('description', PARAM_NOTAGS);
         $mform->addRule('description', null, 'required');
 
         $str = $action == 'new' ? get_string('badgeimage', 'badges') : get_string('newimage', 'badges');
index fadc8ad..c3052f7 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 require_once(dirname(dirname(__FILE__)).'/config.php');
-include_once('lib.php');
-include_once('locallib.php');
+require_once('lib.php');
+require_once('locallib.php');
 
 $action   = required_param('action', PARAM_ALPHA);
 $id       = optional_param('entryid', 0, PARAM_INT);
 $confirm  = optional_param('confirm', 0, PARAM_BOOL);
-$modid    = optional_param('modid', 0, PARAM_INT); // To associate the entry with a module instance
-$courseid = optional_param('courseid', 0, PARAM_INT); // To associate the entry with a course
-
-$PAGE->set_url('/blog/edit.php', array('action' => $action, 'entryid' => $id, 'confirm' => $confirm, 'modid' => $modid, 'courseid' => $courseid));
+$modid = optional_param('modid', 0, PARAM_INT); // To associate the entry with a module instance.
+$courseid = optional_param('courseid', 0, PARAM_INT); // To associate the entry with a course.
 
-// If action is add, we ignore $id to avoid any further problems
-if (!empty($id) && $action == 'add') {
-    $id = null;
+if ($action == 'edit') {
+    $id = required_param('entryid', PARAM_INT);
 }
 
-$returnurl = new moodle_url('/blog/index.php');
+$PAGE->set_url('/blog/edit.php', array('action' => $action,
+                                       'entryid' => $id,
+                                       'confirm' => $confirm,
+                                       'modid' => $modid,
+                                       'courseid' => $courseid));
 
-if (!empty($courseid) && empty($modid)) {
-    $returnurl->param('courseid', $courseid);
-}
-
-// If a modid is given, guess courseid
-if (!empty($modid)) {
-    $returnurl->param('modid', $modid);
-    $courseid = $DB->get_field('course_modules', 'course', array('id' => $modid));
-    $returnurl->param('courseid', $courseid);
+// If action is add, we ignore $id to avoid any further problems.
+if (!empty($id) && $action == 'add') {
+    $id = null;
 }
 
 // Blogs are always in system context.
 $sitecontext = context_system::instance();
 $PAGE->set_context($sitecontext);
 
-
-$blogheaders = blog_get_headers();
-
 require_login($courseid);
 
-if ($action == 'edit') {
-    $id = required_param('entryid', PARAM_INT);
-}
-
 if (empty($CFG->enableblogs)) {
     print_error('blogdisable', 'blog');
 }
@@ -75,11 +62,26 @@ if (isguestuser()) {
     print_error('noguestentry', 'blog');
 }
 
+$returnurl = new moodle_url('/blog/index.php');
+
+if (!empty($courseid) && empty($modid)) {
+    $returnurl->param('courseid', $courseid);
+}
+
+// If a modid is given, guess courseid.
+if (!empty($modid)) {
+    $returnurl->param('modid', $modid);
+    $courseid = $DB->get_field('course_modules', 'course', array('id' => $modid));
+    $returnurl->param('courseid', $courseid);
+}
+
+$blogheaders = blog_get_headers();
+
 if (!has_capability('moodle/blog:create', $sitecontext) && !has_capability('moodle/blog:manageentries', $sitecontext)) {
     print_error('cannoteditentryorblog');
 }
 
-// Make sure that the person trying to edit has access right
+// Make sure that the person trying to edit has access right.
 if ($id) {
     if (!$entry = new blog_entry($id)) {
         print_error('wrongentryid', 'blog');
@@ -94,7 +96,7 @@ if ($id) {
 
 } else {
     if (!has_capability('moodle/blog:create', $sitecontext)) {
-        print_error('noentry', 'blog'); // manageentries is not enough for adding
+        print_error('noentry', 'blog'); // The capability "manageentries" is not enough for adding.
     }
     $entry  = new stdClass();
     $entry->id = null;
@@ -105,14 +107,14 @@ $returnurl->param('userid', $userid);
 // Blog renderer.
 $output = $PAGE->get_renderer('blog');
 
-$strblogs = get_string('blogs','blog');
+$strblogs = get_string('blogs', 'blog');
 
-if ($action === 'delete'){
+if ($action === 'delete') {
     if (empty($entry->id)) {
         print_error('wrongentryid', 'blog');
     }
     if (data_submitted() && $confirm && confirm_sesskey()) {
-        // Make sure the current user is the author of the blog entry, or has some deleteanyentry capability
+        // Make sure the current user is the author of the blog entry, or has some deleteanyentry capability.
         if (!blog_user_can_edit_entry($entry)) {
             print_error('nopermissionstodeleteentry', 'blog');
         } else {
@@ -132,7 +134,9 @@ if ($action === 'delete'){
         echo $output->render($entry);
 
         echo '<br />';
-        echo $OUTPUT->confirm(get_string('blogdeleteconfirm', 'blog'), new moodle_url('edit.php', $optionsyes),new moodle_url( 'index.php', $optionsno));
+        echo $OUTPUT->confirm(get_string('blogdeleteconfirm', 'blog'),
+                              new moodle_url('edit.php', $optionsyes),
+                              new moodle_url('index.php', $optionsno));
         echo $OUTPUT->footer();
         die;
     }
@@ -167,10 +171,21 @@ $summaryoptions = array('maxfiles'=> 99, 'maxbytes'=>$CFG->maxbytes, 'trusttext'
     'subdirs'=>file_area_contains_subdirs($sitecontext, 'blog', 'post', $entry->id));
 $attachmentoptions = array('subdirs'=>false, 'maxfiles'=> 99, 'maxbytes'=>$CFG->maxbytes);
 
-$blogeditform = new blog_edit_form(null, compact('entry', 'summaryoptions', 'attachmentoptions', 'sitecontext', 'courseid', 'modid'));
+$blogeditform = new blog_edit_form(null, compact('entry',
+                                                 'summaryoptions',
+                                                 'attachmentoptions',
+                                                 'sitecontext',
+                                                 'courseid',
+                                                 'modid'));
 
 $entry = file_prepare_standard_editor($entry, 'summary', $summaryoptions, $sitecontext, 'blog', 'post', $entry->id);
-$entry = file_prepare_standard_filemanager($entry, 'attachment', $attachmentoptions, $sitecontext, 'blog', 'attachment', $entry->id);
+$entry = file_prepare_standard_filemanager($entry,
+                                           'attachment',
+                                           $attachmentoptions,
+                                           $sitecontext,
+                                           'blog',
+                                           'attachment',
+                                           $entry->id);
 
 if (!empty($CFG->usetags) && !empty($entry->id)) {
     include_once($CFG->dirroot.'/tag/lib.php');
@@ -178,13 +193,13 @@ if (!empty($CFG->usetags) && !empty($entry->id)) {
 }
 
 $entry->action = $action;
-// set defaults
+// Set defaults.
 $blogeditform->set_data($entry);
 
 if ($blogeditform->is_cancelled()) {
     redirect($returnurl);
 
-} else if ($data = $blogeditform->get_data()){
+} else if ($data = $blogeditform->get_data()) {
 
     switch ($action) {
         case 'add':
@@ -209,23 +224,23 @@ if ($blogeditform->is_cancelled()) {
 }
 
 
-// gui setup
+// GUI setup.
 switch ($action) {
     case 'add':
-        // prepare new empty form
+        // Prepare new empty form.
         $entry->publishstate = 'site';
         $strformheading = get_string('addnewentry', 'blog');
         $entry->action       = $action;
 
         if ($CFG->useblogassociations) {
 
-            //pre-select the course for associations
+            // Pre-select the course for associations.
             if ($courseid) {
                 $context = context_course::instance($courseid);
                 $entry->courseassoc = $context->id;
             }
 
-            //pre-select the mod for associations
+            // Pre-select the mod for associations.
             if ($modid) {
                 $context = context_module::instance($modid);
                 $entry->modassoc = $context->id;
index 2b28a73..805bf79 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -16,7 +15,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 if (!defined('MOODLE_INTERNAL')) {
-    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
+    die('Direct access to this script is forbidden.');    //  It must be included from a Moodle page.
 }
 
 require_once($CFG->libdir.'/formslib.php');
@@ -24,7 +23,10 @@ require_once($CFG->libdir.'/formslib.php');
 class blog_edit_form extends moodleform {
     public $modnames = array();
 
-    function definition() {
+    /**
+     * Blog form definition.
+     */
+    public function definition() {
         global $CFG, $DB;
 
         $mform =& $this->_form;
@@ -50,12 +52,12 @@ class blog_edit_form extends moodleform {
 
         $mform->addElement('filemanager', 'attachment_filemanager', get_string('attachment', 'forum'), null, $attachmentoptions);
 
-        //disable publishstate options that are not allowed
+        // Disable publishstate options that are not allowed.
         $publishstates = array();
         $i = 0;
 
         foreach (blog_entry::get_applicable_publish_states() as $state => $desc) {
-            $publishstates[$state] = $desc;   //no maximum was set
+            $publishstates[$state] = $desc;   // No maximum was set.
             $i++;
         }
 
@@ -87,7 +89,12 @@ class blog_edit_form extends moodleform {
                 }
 
                 $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
-                $mform->addElement('advcheckbox', 'courseassoc', get_string('associatewithcourse', 'blog', $a), null, null, array(0, $contextid));
+                $mform->addElement('advcheckbox',
+                                   'courseassoc',
+                                   get_string('associatewithcourse', 'blog', $a),
+                                   null,
+                                   null,
+                                   array(0, $contextid));
                 $mform->setDefault('courseassoc', $contextid);
 
             } else if ((!empty($entry->modassoc) || !empty($modid))) {
@@ -107,7 +114,12 @@ class blog_edit_form extends moodleform {
                 }
 
                 $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
-                $mform->addElement('advcheckbox', 'modassoc', get_string('associatewithmodule', 'blog', $a), null, null, array(0, $context->id));
+                $mform->addElement('advcheckbox',
+                                   'modassoc',
+                                   get_string('associatewithmodule', 'blog', $a),
+                                   null,
+                                   null,
+                                   array(0, $context->id));
                 $mform->setDefault('modassoc', $context->id);
             }
         }
@@ -130,12 +142,18 @@ class blog_edit_form extends moodleform {
         $mform->setDefault('courseid', $courseid);
     }
 
-    function validation($data, $files) {
+    /**
+     * Validate the blog form data.
+     * @param array $data Data to be validated
+     * @param array $files unused
+     * @return array|bool
+     */
+    public function validation($data, $files) {
         global $CFG, $DB, $USER;
 
         $errors = array();
 
-        // validate course association
+        // Validate course association.
         if (!empty($data['courseassoc'])) {
             $coursecontext = context::instance_by_id($data['courseassoc']);
 
@@ -144,16 +162,16 @@ class blog_edit_form extends moodleform {
             }
         }
 
-        // validate mod association
+        // Validate mod association.
         if (!empty($data['modassoc'])) {
             $modcontextid = $data['modassoc'];
             $modcontext = context::instance_by_id($modcontextid);
 
             if ($modcontext->contextlevel == CONTEXT_MODULE) {
-                // get context of the mod's course
+                // Get context of the mod's course.
                 $coursecontext = $modcontext->get_course_context(true);
 
-                // ensure only one course is associated
+                // Ensure only one course is associated.
                 if (!empty($data['courseassoc'])) {
                     if ($data['courseassoc'] != $coursecontext->id) {
                         $errors['modassoc'] = get_string('onlyassociateonecourse', 'blog');
index b28860a..0aa122b 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -35,7 +34,9 @@ require_login();
 $context = context_system::instance();
 require_capability('moodle/blog:manageexternal', $context);
 
-// TODO redirect if $CFG->useexternalblogs is off, $CFG->maxexternalblogsperuser == 0, or if user doesn't have caps to manage external blogs
+// TODO redirect if $CFG->useexternalblogs is off,
+//                  $CFG->maxexternalblogsperuser == 0,
+//                  or if user doesn't have caps to manage external blogs.
 
 $id = optional_param('id', null, PARAM_INT);
 $url = new moodle_url('/blog/external_blog_edit.php');
@@ -52,24 +53,24 @@ $action = (empty($id)) ? 'add' : 'edit';
 
 $external = new stdClass();
 
-// Check that this id exists
+// Check that this id exists.
 if (!empty($id) && !$DB->record_exists('blog_external', array('id' => $id))) {
     print_error('wrongexternalid', 'blog');
-} elseif (!empty($id)) {
+} else if (!empty($id)) {
     $external = $DB->get_record('blog_external', array('id' => $id));
 }
 
 $strformheading = ($action == 'edit') ? get_string('editexternalblog', 'blog') : get_string('addnewexternalblog', 'blog');
-$strexternalblogs = get_string('externalblogs','blog');
-$strblogs = get_string('blogs','blog');
+$strexternalblogs = get_string('externalblogs', 'blog');
+$strblogs = get_string('blogs', 'blog');
 
 $externalblogform = new blog_edit_external_form();
 
-if ($externalblogform->is_cancelled()){
+if ($externalblogform->is_cancelled()) {
     redirect($returnurl);
 
 } else if ($data = $externalblogform->get_data()) {
-    //save stuff in db
+    // Save stuff in db.
     switch ($action) {
         case 'add':
             $rss = new moodle_simplepie($data->url);
@@ -79,13 +80,16 @@ if ($externalblogform->is_cancelled()){
             $newexternal->description = (empty($data->description)) ? $rss->get_description() : $data->description;
             $newexternal->userid = $USER->id;
             $newexternal->url = $data->url;
-            $newexternal->filtertags = $data->filtertags;
+            $newexternal->filtertags = (!empty($data->filtertags)) ? $data->filtertags : null;
             $newexternal->timemodified = time();
 
             $newexternal->id = $DB->insert_record('blog_external', $newexternal);
             blog_sync_external_entries($newexternal);
-            tag_set('blog_external', $newexternal->id, explode(',', $data->autotags), 'core',
-                context_user::instance($newexternal->userid)->id);
+            if ($CFG->usetags) {
+                $autotags = (!empty($data->autotags)) ? $data->autotags : null;
+                tag_set('blog_external', $newexternal->id, explode(',', $autotags), 'core',
+                    context_user::instance($newexternal->userid)->id);
+            }
 
             break;
 
@@ -99,13 +103,15 @@ if ($externalblogform->is_cancelled()){
                 $external->description = (empty($data->description)) ? $rss->get_description() : $data->description;
                 $external->userid = $USER->id;
                 $external->url = $data->url;
-                $external->filtertags = $data->filtertags;
+                $external->filtertags = (!empty($data->filtertags)) ? $data->filtertags : null;
                 $external->timemodified = time();
 
                 $DB->update_record('blog_external', $external);
-                tag_set('blog_external', $external->id, explode(',', $data->autotags), 'core',
-                    context_user::instance($newexternal->userid)->id);
-
+                if ($CFG->usetags) {
+                    $autotags = (!empty($data->autotags)) ? $data->autotags : null;
+                    tag_set('blog_external', $external->id, explode(',', $autotags), 'core',
+                        context_user::instance($external->userid)->id);
+                }
             } else {
                 print_error('wrongexternalid', 'blog');
             }
index 696e79a..fc28e9a 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -26,7 +25,7 @@
  */
 
 if (!defined('MOODLE_INTERNAL')) {
-    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
+    die('Direct access to this script is forbidden.');    // It must be included from a Moodle page.
 }
 
 require_once($CFG->libdir.'/formslib.php');
@@ -118,9 +117,11 @@ class blog_edit_external_form extends moodleform {
         if ($id = $mform->getElementValue('id')) {
             $mform->setDefault('autotags', implode(',', tag_get_tags_array('blog_external', $id)));
             $mform->freeze('url');
-            $mform->freeze('filtertags');
+            if ($mform->elementExists('filtertags')) {
+                $mform->freeze('filtertags');
+            }
             // TODO change the filtertags element to a multiple select, using the tags of the external blog
-            // Use $rss->get_channel_tags()
+            // Use $rss->get_channel_tags().
         }
     }
 }
index 57af11a..800c85c 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -36,23 +35,25 @@ require_capability('moodle/blog:manageexternal', $context);
 
 $delete = optional_param('delete', null, PARAM_INT);
 
-$strexternalblogs = get_string('externalblogs','blog');
-$straddnewexternalblog = get_string('addnewexternalblog','blog');
-$strblogs = get_string('blogs','blog');
+$strexternalblogs = get_string('externalblogs', 'blog');
+$straddnewexternalblog = get_string('addnewexternalblog', 'blog');
+$strblogs = get_string('blogs', 'blog');
 $message = null;
 
 if ($delete && confirm_sesskey()) {
     $externalbloguserid = $DB->get_field('blog_external', 'userid', array('id' => $delete));
     if ($externalbloguserid == $USER->id) {
-        // Delete the external blog
+        // Delete the external blog.
         $DB->delete_records('blog_external', array('id' => $delete));
 
-        // Delete the external blog's posts
+        // Delete the external blog's posts.
         $deletewhere = 'module = :module
                             AND userid = :userid
                             AND ' . $DB->sql_isnotempty('post', 'uniquehash', false, false) . '
                             AND ' . $DB->sql_compare_text('content') . ' = ' . $DB->sql_compare_text(':delete');
-        $DB->delete_records_select('post', $deletewhere, array('module' => 'blog_external', 'userid' => $USER->id, 'delete' => $delete));
+        $DB->delete_records_select('post', $deletewhere, array('module' => 'blog_external',
+                                                               'userid' => $USER->id,
+                                                               'delete' => $delete));
 
         $message = get_string('externalblogdeleted', 'blog');
     }
@@ -77,7 +78,11 @@ if (!empty($blogs)) {
     $table = new html_table();
     $table->cellpadding = 4;
     $table->attributes['class'] = 'generaltable boxaligncenter';
-    $table->head = array(get_string('name'), get_string('url', 'blog'), get_string('timefetched', 'blog'), get_string('valid', 'blog'), get_string('actions'));
+    $table->head = array(get_string('name'),
+                         get_string('url', 'blog'),
+                         get_string('timefetched', 'blog'),
+                         get_string('valid', 'blog'),
+                         get_string('actions'));
 
     foreach ($blogs as $blog) {
         if ($blog->failedlastsync) {
@@ -92,7 +97,11 @@ if (!empty($blogs)) {
         $deletelink = new moodle_url('/blog/external_blogs.php', array('delete' => $blog->id, 'sesskey'=>sesskey()));
         $deleteicon = $OUTPUT->action_icon($deletelink, new pix_icon('t/delete', get_string('deleteexternalblog', 'blog')));
 
-        $table->data[] = new html_table_row(array($blog->name, $blog->url, userdate($blog->timefetched), $validicon, $editicon . '&nbsp'. $deleteicon));
+        $table->data[] = new html_table_row(array($blog->name,
+                                                  $blog->url,
+                                                  userdate($blog->timefetched),
+                                                  $validicon,
+                                                  $editicon . '&nbsp'. $deleteicon));
     }
     echo html_writer::table($table);
 }
index efa99ea..4c58f34 100644 (file)
@@ -1,4 +1,18 @@
 <?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/>.
 
 /**
  * file index.php
@@ -34,11 +48,7 @@ foreach ($url_params as $var => $val) {
 }
 $PAGE->set_url('/blog/index.php', $url_params);
 
-if (empty($CFG->enableblogs)) {
-    print_error('blogdisable', 'blog');
-}
-
-//correct tagid if a text tag is provided as a param
+// Correct tagid if a text tag is provided as a param.
 if (!empty($tag)) {
     if ($tagrec = $DB->get_record('tag', array('name' => $tag))) {
         $tagid = $tagrec->id;
@@ -47,43 +57,47 @@ if (!empty($tag)) {
     }
 }
 
-// add courseid if modid or groupid is specified: This is used for navigation and title
-if (!empty($modid) && empty($courseid)) {
-    $courseid = $DB->get_field('course_modules', 'course', array('id'=>$modid));
-}
-
-if (!empty($groupid) && empty($courseid)) {
-    $courseid = $DB->get_field('groups', 'courseid', array('id'=>$groupid));
-}
-
 $sitecontext = context_system::instance();
 // Blogs are always in system context.
 $PAGE->set_context($sitecontext);
 
-// check basic permissions
+// Check basic permissions.
 if ($CFG->bloglevel == BLOG_GLOBAL_LEVEL) {
-    // everybody can see anything - no login required unless site is locked down using forcelogin
+    // Everybody can see anything - no login required unless site is locked down using forcelogin.
     if ($CFG->forcelogin) {
         require_login();
     }
 
 } else if ($CFG->bloglevel == BLOG_SITE_LEVEL) {
-    // users must log in and can not be guests
+    // Users must log in and can not be guests.
     require_login();
     if (isguestuser()) {
-        // they must have entered the url manually...
+        // They must have entered the url manually.
         print_error('blogdisable', 'blog');
     }
 
 } else if ($CFG->bloglevel == BLOG_USER_LEVEL) {
-    // users can see own blogs only! with the exception of ppl with special cap
+    // Users can see own blogs only! with the exception of people with special cap.
     require_login();
 
 } else {
-    // weird!
+    // Weird!
     print_error('blogdisable', 'blog');
 }
 
+if (empty($CFG->enableblogs)) {
+    print_error('blogdisable', 'blog');
+}
+
+// Add courseid if modid or groupid is specified: This is used for navigation and title.
+if (!empty($modid) && empty($courseid)) {
+    $courseid = $DB->get_field('course_modules', 'course', array('id' => $modid));
+}
+
+if (!empty($groupid) && empty($courseid)) {
+    $courseid = $DB->get_field('groups', 'courseid', array('id' => $groupid));
+}
+
 
 if (!$userid && has_capability('moodle/blog:view', $sitecontext) && $CFG->bloglevel > BLOG_USER_LEVEL) {
     if ($entryid) {
@@ -206,13 +220,10 @@ if ($CFG->enablerssfeeds) {
     }
     $rsstitle = $blogheaders['heading'];
 
-    //check we haven't started output by outputting an error message
+    // Check we haven't started output by outputting an error message.
     if ($PAGE->state == moodle_page::STATE_BEFORE_HEADER) {
         blog_rss_add_http_header($rsscontext, $rsstitle, $filtertype, $thingid, $tagid);
     }
-
-    //this works but there isn't a great place to put the link
-    //blog_rss_print_link($rsscontext, $filtertype, $thingid, $tagid);
 }
 
 echo $OUTPUT->header();
index 9190e46..5b26916 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -26,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-/**
+/*
  * Library of functions and constants for blog
  */
 require_once($CFG->dirroot .'/blog/rsslib.php');
@@ -45,11 +44,11 @@ function blog_user_can_edit_entry($blogentry) {
     $sitecontext = context_system::instance();
 
     if (has_capability('moodle/blog:manageentries', $sitecontext)) {
-        return true; // can edit any blog entry
+        return true; // Can edit any blog entry.
     }
 
     if ($blogentry->userid == $USER->id && has_capability('moodle/blog:create', $sitecontext)) {
-        return true; // can edit own when having blog:create capability
+        return true; // Can edit own when having blog:create capability.
     }
 
     return false;
@@ -168,12 +167,12 @@ function blog_sync_external_entries($externalblog) {
     if (empty($rss->data)) {
         return null;
     }
-    //used to identify blog posts that have been deleted from the source feed
+    // Used to identify blog posts that have been deleted from the source feed.
     $oldesttimestamp = null;
     $uniquehashes = array();
 
     foreach ($rss->get_items() as $entry) {
-        // If filtertags are defined, use them to filter the entries by RSS category
+        // If filtertags are defined, use them to filter the entries by RSS category.
         if (!empty($externalblog->filtertags)) {
             $containsfiltertag = false;
             $categories = $entry->get_categories();
@@ -201,26 +200,26 @@ function blog_sync_external_entries($externalblog) {
         $newentry->uniquehash = $entry->get_permalink();
         $newentry->publishstate = 'site';
         $newentry->format = FORMAT_HTML;
-        // Clean subject of html, just in case
+        // Clean subject of html, just in case.
         $newentry->subject = clean_param($entry->get_title(), PARAM_TEXT);
-        // Observe 128 max chars in DB
-        // TODO: +1 to raise this to 255
+        // Observe 128 max chars in DB.
+        // TODO: +1 to raise this to 255.
         if (core_text::strlen($newentry->subject) > 128) {
             $newentry->subject = core_text::substr($newentry->subject, 0, 125) . '...';
         }
         $newentry->summary = $entry->get_description();
 
-        //used to decide whether to insert or update
-        //uses enty permalink plus creation date if available
+        // Used to decide whether to insert or update.
+        // Uses enty permalink plus creation date if available.
         $existingpostconditions = array('uniquehash' => $entry->get_permalink());
 
-        //our DB doesnt allow null creation or modified timestamps so check the external blog supplied one
+        // Our DB doesnt allow null creation or modified timestamps so check the external blog supplied one.
         $entrydate = $entry->get_date('U');
         if (!empty($entrydate)) {
             $existingpostconditions['created'] = $entrydate;
         }
 
-        //the post ID or false if post not found in DB
+        // The post ID or false if post not found in DB.
         $postid = $DB->get_field('post', 'id', $existingpostconditions);
 
         $timestamp = null;
@@ -230,14 +229,14 @@ function blog_sync_external_entries($externalblog) {
             $timestamp = $entrydate;
         }
 
-        //only set created if its a new post so we retain the original creation timestamp if the post is edited
+        // Only set created if its a new post so we retain the original creation timestamp if the post is edited.
         if ($postid === false) {
             $newentry->created = $timestamp;
         }
         $newentry->lastmodified = $timestamp;
 
         if (empty($oldesttimestamp) || $timestamp < $oldesttimestamp) {
-            //found an older post
+            // Found an older post.
             $oldesttimestamp = $timestamp;
         }
 
@@ -252,7 +251,7 @@ function blog_sync_external_entries($externalblog) {
         if ($postid === false) {
             $id = $DB->insert_record('post', $newentry);
 
-            // Set tags
+            // Set tags.
             if ($tags = tag_get_tags_array('blog_external', $externalblog->id)) {
                 tag_set('post', $id, $tags, 'core', context_user::instance($externalblog->userid)->id);
             }
@@ -273,7 +272,7 @@ function blog_sync_external_entries($externalblog) {
     $dbposts = $DB->get_records_sql($sql, array('blogid' => $externalblog->id, 'ts' => $oldesttimestamp));
 
     $todelete = array();
-    foreach($dbposts as $dbpost) {
+    foreach ($dbposts as $dbpost) {
         if ( !in_array($dbpost->uniquehash, $uniquehashes) ) {
             $todelete[] = $dbpost->id;
         }
@@ -324,13 +323,13 @@ function blog_get_all_options(moodle_page $page, stdClass $userid = null) {
 
     $options = array();
 
-    // If blogs are enabled and the user is logged in and not a guest
+    // If blogs are enabled and the user is logged in and not a guest.
     if (blog_is_enabled_for_user()) {
-        // If the context is the user then assume we want to load for the users context
+        // If the context is the user then assume we want to load for the users context.
         if (is_null($userid) && $page->context->contextlevel == CONTEXT_USER) {
             $userid = $page->context->instanceid;
         }
-        // Check the userid var
+        // Check the userid var.
         if (!is_null($userid) && $userid!==$USER->id) {
             // Load the user from the userid... it MUST EXIST throw a wobbly if it doesn't!
             $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
@@ -339,33 +338,36 @@ function blog_get_all_options(moodle_page $page, stdClass $userid = null) {
         }
 
         if ($CFG->useblogassociations && $page->cm !== null) {
-            // Load for the module associated with the page
+            // Load for the module associated with the page.
             $options[CONTEXT_MODULE] = blog_get_options_for_module($page->cm, $user);
         } else if ($CFG->useblogassociations && $page->course->id != SITEID) {
-            // Load the options for the course associated with the page
+            // Load the options for the course associated with the page.
             $options[CONTEXT_COURSE] = blog_get_options_for_course($page->course, $user);
         }
 
-        // Get the options for the user
+        // Get the options for the user.
         if ($user !== null and !isguestuser($user)) {
-            // Load for the requested user
+            // Load for the requested user.
             $options[CONTEXT_USER+1] = blog_get_options_for_user($user);
         }
-        // Load for the current user
+        // Load for the current user.
         if (isloggedin() and !isguestuser()) {
             $options[CONTEXT_USER] = blog_get_options_for_user();
         }
     }
 
-    // If blog level is global then display a link to view all site entries
-    if (!empty($CFG->enableblogs) && $CFG->bloglevel >= BLOG_GLOBAL_LEVEL && has_capability('moodle/blog:view', context_system::instance())) {
+    // If blog level is global then display a link to view all site entries.
+    if (!empty($CFG->enableblogs)
+        && $CFG->bloglevel >= BLOG_GLOBAL_LEVEL
+        && has_capability('moodle/blog:view', context_system::instance())) {
+
         $options[CONTEXT_SYSTEM] = array('viewsite' => array(
             'string' => get_string('viewsiteentries', 'blog'),
             'link' => new moodle_url('/blog/index.php')
         ));
     }
 
-    // Return the options
+    // Return the options.
     return $options;
 }
 
@@ -380,16 +382,16 @@ function blog_get_all_options(moodle_page $page, stdClass $userid = null) {
  */
 function blog_get_options_for_user(stdClass $user=null) {
     global $CFG, $USER;
-    // Cache
+    // Cache.
     static $useroptions = array();
 
     $options = array();
-    // Blogs must be enabled and the user must be logged in
+    // Blogs must be enabled and the user must be logged in.
     if (!blog_is_enabled_for_user()) {
         return $options;
     }
 
-    // Sort out the user var
+    // Sort out the user var.
     if ($user === null || $user->id == $USER->id) {
         $user = $USER;
         $iscurrentuser = true;
@@ -397,7 +399,7 @@ function blog_get_options_for_user(stdClass $user=null) {
         $iscurrentuser = false;
     }
 
-    // If we've already generated serve from the cache
+    // If we've already generated serve from the cache.
     if (array_key_exists($user->id, $useroptions)) {
         return $useroptions[$user->id];
     }
@@ -406,22 +408,22 @@ function blog_get_options_for_user(stdClass $user=null) {
     $canview = has_capability('moodle/blog:view', $sitecontext);
 
     if (!$iscurrentuser && $canview && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) {
-        // Not the current user, but we can view and its blogs are enabled for SITE or GLOBAL
+        // Not the current user, but we can view and its blogs are enabled for SITE or GLOBAL.
         $options['userentries'] = array(
             'string' => get_string('viewuserentries', 'blog', fullname($user)),
             'link' => new moodle_url('/blog/index.php', array('userid'=>$user->id))
         );
     } else {
-        // It's the current user
+        // It's the current user.
         if ($canview) {
-            // We can view our own blogs .... BIG surprise
+            // We can view our own blogs .... BIG surprise.
             $options['view'] = array(
                 'string' => get_string('viewallmyentries', 'blog'),
                 'link' => new moodle_url('/blog/index.php', array('userid'=>$USER->id))
             );
         }
         if (has_capability('moodle/blog:create', $sitecontext)) {
-            // We can add to our own blog
+            // We can add to our own blog.
             $options['add'] = array(
                 'string' => get_string('addnewentry', 'blog'),
                 'link' => new moodle_url('/blog/edit.php', array('action'=>'add'))
@@ -432,12 +434,12 @@ function blog_get_options_for_user(stdClass $user=null) {
         $options['rss'] = array(
             'string' => get_string('rssfeed', 'blog'),
             'link' => new moodle_url(rss_get_url($sitecontext->id, $USER->id, 'blog', 'user/'.$user->id))
-       );
+        );
     }
 
-    // Cache the options
+    // Cache the options.
     $useroptions[$user->id] = $options;
-    // Return the options
+    // Return the options.
     return $options;
 }
 
@@ -451,47 +453,46 @@ function blog_get_options_for_user(stdClass $user=null) {
  */
 function blog_get_options_for_course(stdClass $course, stdClass $user=null) {
     global $CFG, $USER;
-    // Cache
+    // Cache.
     static $courseoptions = array();
 
     $options = array();
 
-    // User must be logged in and blogs must be enabled
+    // User must be logged in and blogs must be enabled.
     if (!blog_is_enabled_for_user()) {
         return $options;
     }
 
-    // Check that the user can associate with the course
+    // Check that the user can associate with the course.
     $sitecontext = context_system::instance();
-    // Generate the cache key
+    // Generate the cache key.
     $key = $course->id.':';
     if (!empty($user)) {
         $key .= $user->id;
     } else {
         $key .= $USER->id;
     }
-    // Serve from the cache if we've already generated for this course
+    // Serve from the cache if we've already generated for this course.
     if (array_key_exists($key, $courseoptions)) {
         return $courseoptions[$key];
     }
 
-
     if (has_capability('moodle/blog:view', $sitecontext)) {
         // We can view!
         if ($CFG->bloglevel >= BLOG_SITE_LEVEL) {
-            // View entries about this course
+            // View entries about this course.
             $options['courseview'] = array(
                 'string' => get_string('viewcourseblogs', 'blog'),
                 'link' => new moodle_url('/blog/index.php', array('courseid' => $course->id))
             );
         }
-        // View MY entries about this course
+        // View MY entries about this course.
         $options['courseviewmine'] = array(
             'string' => get_string('viewmyentriesaboutcourse', 'blog'),
             'link' => new moodle_url('/blog/index.php', array('courseid' => $course->id, 'userid' => $USER->id))
         );
         if (!empty($user) && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) {
-            // View the provided users entries about this course
+            // View the provided users entries about this course.
             $options['courseviewuser'] = array(
                 'string' => get_string('viewentriesbyuseraboutcourse', 'blog', fullname($user)),
                 'link' => new moodle_url('/blog/index.php', array('courseid' => $course->id, 'userid' => $user->id))
@@ -500,17 +501,16 @@ function blog_get_options_for_course(stdClass $course, stdClass $user=null) {
     }
 
     if (has_capability('moodle/blog:create', $sitecontext)) {
-        // We can blog about this course
+        // We can blog about this course.
         $options['courseadd'] = array(
             'string' => get_string('blogaboutthiscourse', 'blog'),
             'link' => new moodle_url('/blog/edit.php', array('action' => 'add', 'courseid' => $course->id))
         );
     }
 
-
-    // Cache the options for this course
+    // Cache the options for this course.
     $courseoptions[$key] = $options;
-    // Return the options
+    // Return the options.
     return $options;
 }
 
@@ -524,18 +524,18 @@ function blog_get_options_for_course(stdClass $course, stdClass $user=null) {
  */
 function blog_get_options_for_module($module, $user=null) {
     global $CFG, $USER;
-    // Cache
+    // Cache.
     static $moduleoptions = array();
 
     $options = array();
-    // User must be logged in, blogs must be enabled
+    // User must be logged in, blogs must be enabled.
     if (!blog_is_enabled_for_user()) {
         return $options;
     }
 
     $sitecontext = context_system::instance();
 
-    // Generate the cache key
+    // Generate the cache key.
     $key = $module->id.':';
     if (!empty($user)) {
         $key .= $user->id;
@@ -543,18 +543,17 @@ function blog_get_options_for_module($module, $user=null) {
         $key .= $USER->id;
     }
     if (array_key_exists($key, $moduleoptions)) {
-        // Serve from the cache so we don't have to regenerate
+        // Serve from the cache so we don't have to regenerate.
         return $moduleoptions[$key];
     }
 
-
     if (has_capability('moodle/blog:view', $sitecontext)) {
         // Save correct module name for later usage.
         $modulename = get_string('modulename', $module->modname);
 
         // We can view!
         if ($CFG->bloglevel >= BLOG_SITE_LEVEL) {
-            // View all entries about this module
+            // View all entries about this module.
             $a = new stdClass;
             $a->type = $modulename;
             $options['moduleview'] = array(
@@ -562,13 +561,13 @@ function blog_get_options_for_module($module, $user=null) {
                 'link' => new moodle_url('/blog/index.php', array('modid'=>$module->id))
             );
         }
-        // View MY entries about this module
+        // View MY entries about this module.
         $options['moduleviewmine'] = array(
             'string' => get_string('viewmyentriesaboutmodule', 'blog', $modulename),
             'link' => new moodle_url('/blog/index.php', array('modid'=>$module->id, 'userid'=>$USER->id))
         );
         if (!empty($user) && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) {
-            // View the given users entries about this module
+            // View the given users entries about this module.
             $a = new stdClass;
             $a->mod = $modulename;
             $a->user = fullname($user);
@@ -580,15 +579,15 @@ function blog_get_options_for_module($module, $user=null) {
     }
 
     if (has_capability('moodle/blog:create', $sitecontext)) {
-        // The user can blog about this module
+        // The user can blog about this module.
         $options['moduleadd'] = array(
             'string' => get_string('blogaboutthismodule', 'blog', $modulename),
             'link' => new moodle_url('/blog/edit.php', array('action'=>'add', 'modid'=>$module->id))
         );
     }
-    // Cache the options
+    // Cache the options.
     $moduleoptions[$key] = $options;
-    // Return the options
+    // Return the options.
     return $options;
 }
 
@@ -626,7 +625,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
     $action   = optional_param('action', null, PARAM_ALPHA);
     $confirm  = optional_param('confirm', false, PARAM_BOOL);
 
-    // Ignore userid when action == add
+    // Ignore userid when action == add.
     if ($action == 'add' && $userid) {
         unset($userid);
         $PAGE->url->remove_params(array('userid'));
@@ -644,11 +643,11 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
 
     $site = $DB->get_record('course', array('id' => SITEID));
     $sitecontext = context_system::instance();
-    // Common Lang strings
+    // Common Lang strings.
     $strparticipants = get_string("participants");
     $strblogentries  = get_string("blogentries", 'blog');
 
-    // Prepare record objects as needed
+    // Prepare record objects as needed.
     if (!empty($courseid)) {
         $headers['filters']['course'] = $courseid;
         $course = $DB->get_record('course', array('id' => $courseid));
@@ -659,7 +658,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $user = $DB->get_record('user', array('id' => $userid));
     }
 
-    if (!empty($groupid)) { // groupid always overrides courseid
+    if (!empty($groupid)) { // The groupid always overrides courseid.
         $headers['filters']['group'] = $groupid;
         $group = $DB->get_record('groups', array('id' => $groupid));
         $course = $DB->get_record('course', array('id' => $group->courseid));
@@ -667,11 +666,11 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
 
     $PAGE->set_pagelayout('standard');
 
-    // modid always overrides courseid, so the $course object may be reset here
+    // The modid always overrides courseid, so the $course object may be reset here.
     if (!empty($modid) && $CFG->useblogassociations) {
 
         $headers['filters']['module'] = $modid;
-        // A groupid param may conflict with this coursemod's courseid. Ignore groupid in that case
+        // A groupid param may conflict with this coursemod's courseid. Ignore groupid in that case.
         $courseid = $DB->get_field('course_modules', 'course', array('id'=>$modid));
         $course = $DB->get_record('course', array('id' => $courseid));
         $cm = $DB->get_record('course_modules', array('id' => $modid));
@@ -685,17 +684,16 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
     }
 
     // Case 1: No entry, mod, course or user params: all site entries to be shown (filtered by search and tag/tagid)
-    // Note: if action is set to 'add' or 'edit', we do this at the end
+    // Note: if action is set to 'add' or 'edit', we do this at the end.
     if (empty($entryid) && empty($modid) && empty($courseid) && empty($userid) && !in_array($action, array('edit', 'add'))) {
         $shortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $PAGE->navbar->add($strblogentries, $blogurl);
         $PAGE->set_title("$shortname: " . get_string('blog', 'blog'));
         $PAGE->set_heading("$shortname: " . get_string('blog', 'blog'));
         $headers['heading'] = get_string('siteblog', 'blog', $shortname);
-        // $headers['strview'] = get_string('viewsiteentries', 'blog');
     }
 
-    // Case 2: only entryid is requested, ignore all other filters. courseid is used to give more contextual information
+    // Case 2: only entryid is requested, ignore all other filters. courseid is used to give more contextual information.
     if (!empty($entryid)) {
         $headers['filters']['entry'] = $entryid;
         $sql = 'SELECT u.* FROM {user} u, {post} p WHERE p.id = ? AND p.userid = u.id';
@@ -720,15 +718,16 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $PAGE->set_heading("$shortname: " . fullname($user) . ": $entry->subject");
         $headers['heading'] = get_string('blogentrybyuser', 'blog', fullname($user));
 
-        // We ignore tag and search params
+        // We ignore tag and search params.
         if (empty($action) || !$CFG->useblogassociations) {
             $headers['url'] = $blogurl;
             return $headers;
         }
     }
 
-    // Case 3: A user's blog entries
     if (!empty($userid) && empty($entryid) && ((empty($courseid) && empty($modid)) || !$CFG->useblogassociations)) {
+        // Case 3: A user's blog entries.
+
         $shortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $blogurl->param('userid', $userid);
         $PAGE->set_title("$shortname: " . fullname($user) . ": " . get_string('blog', 'blog'));
@@ -736,23 +735,21 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $headers['heading'] = get_string('userblog', 'blog', fullname($user));
         $headers['strview'] = get_string('viewuserentries', 'blog', fullname($user));
 
-    } else
+    } else if (!$CFG->useblogassociations && empty($userid) && !in_array($action, array('edit', 'add'))) {
+        // Case 4: No blog associations, no userid.
 
-    // Case 4: No blog associations, no userid
-    if (!$CFG->useblogassociations && empty($userid) && !in_array($action, array('edit', 'add'))) {
         $shortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $PAGE->set_title("$shortname: " . get_string('blog', 'blog'));
         $PAGE->set_heading("$shortname: " . get_string('blog', 'blog'));
         $headers['heading'] = get_string('siteblog', 'blog', $shortname);
-    } else
+    } else if (!empty($userid) && !empty($modid) && empty($entryid)) {
+        // Case 5: Blog entries associated with an activity by a specific user (courseid ignored).
 
-    // Case 5: Blog entries associated with an activity by a specific user (courseid ignored)
-    if (!empty($userid) && !empty($modid) && empty($entryid)) {
         $shortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $blogurl->param('userid', $userid);
         $blogurl->param('modid', $modid);
 
-        // Course module navigation is handled by build_navigation as the second param
+        // Course module navigation is handled by build_navigation as the second param.
         $headers['cm'] = $cm;
         $PAGE->navbar->add(fullname($user), "$CFG->wwwroot/user/view.php?id=$user->id");
         $PAGE->navbar->add($strblogentries, $blogurl);
@@ -767,10 +764,9 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $headers['heading'] = get_string('blogentriesbyuseraboutmodule', 'blog', $a);
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewallmodentries', 'blog', $a);
-    } else
+    } else if (!empty($userid) && !empty($courseid) && empty($modid) && empty($entryid)) {
+        // Case 6: Blog entries associated with a course by a specific user.
 
-    // Case 6: Blog entries associated with a course by a specific user
-    if (!empty($userid) && !empty($courseid) && empty($modid) && empty($entryid)) {
         $siteshortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
         $blogurl->param('userid', $userid);
@@ -789,12 +785,11 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewblogentries', 'blog', $a);
 
-        // Remove the userid from the URL to inform the blog_menu block correctly
+        // Remove the userid from the URL to inform the blog_menu block correctly.
         $blogurl->remove_params(array('userid'));
-    } else
+    } else if (!empty($groupid) && empty($modid) && empty($entryid)) {
+        // Case 7: Blog entries by members of a group, associated with that group's course.
 
-    // Case 7: Blog entries by members of a group, associated with that group's course
-    if (!empty($groupid) && empty($modid) && empty($entryid)) {
         $siteshortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
         $blogurl->param('courseid', $course->id);
@@ -814,10 +809,9 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $headers['heading'] = get_string('blogentriesbygroupaboutcourse', 'blog', $a);
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewblogentries', 'blog', $a);
-    } else
+    } else if (!empty($groupid) && !empty($modid) && empty($entryid)) {
+        // Case 8: Blog entries by members of a group, associated with an activity in that course.
 
-    // Case 8: Blog entries by members of a group, associated with an activity in that course
-    if (!empty($groupid) && !empty($modid) && empty($entryid)) {
         $siteshortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
         $headers['cm'] = $cm;
@@ -838,10 +832,9 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewallmodentries', 'blog', $a);
 
-    } else
+    } else if (!empty($modid) && empty($userid) && empty($groupid) && empty($entryid)) {
+        // Case 9: All blog entries associated with an activity.
 
-    // Case 9: All blog entries associated with an activity
-    if (!empty($modid) && empty($userid) && empty($groupid) && empty($entryid)) {
         $siteshortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
         $PAGE->set_cm($cm, $course);
@@ -854,10 +847,9 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $a->type = get_string('modulename', $cm->modname);
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewallmodentries', 'blog', $a);
-    } else
+    } else if (!empty($courseid) && empty($userid) && empty($groupid) && empty($modid) && empty($entryid)) {
+        // Case 10: All blog entries associated with a course.
 
-    // Case 10: All blog entries associated with a course
-    if (!empty($courseid) && empty($userid) && empty($groupid) && empty($modid) && empty($entryid)) {
         $siteshortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
         $blogurl->param('courseid', $courseid);
@@ -866,20 +858,24 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $PAGE->set_heading("$siteshortname: $courseshortname: " . get_string('blogentries', 'blog'));
         $a = new stdClass();
         $a->type = get_string('course');
-        $headers['heading'] = get_string('blogentriesabout', 'blog', format_string($course->fullname, true, array('context' => context_course::instance($course->id))));
+        $headers['heading'] = get_string('blogentriesabout',
+                                         'blog',
+                                         format_string($course->fullname,
+                                                       true,
+                                                       array('context' => context_course::instance($course->id))));
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewblogentries', 'blog', $a);
         $blogurl->remove_params(array('userid'));
     }
 
     if (!in_array($action, array('edit', 'add'))) {
-        // Append Tag info
+        // Append Tag info.
         if (!empty($tagid)) {
             $headers['filters']['tag'] = $tagid;
             $blogurl->param('tagid', $tagid);
             $tagrec = $DB->get_record('tag', array('id'=>$tagid));
             $PAGE->navbar->add($tagrec->name, $blogurl);
-        } elseif (!empty($tag)) {
+        } else if (!empty($tag)) {
             if ($tagrec = $DB->get_record('tag', array('name' => $tag))) {
                 $tagid = $tagrec->id;
                 $headers['filters']['tag'] = $tagid;
@@ -888,7 +884,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
             }
         }
 
-        // Append Search info
+        // Append Search info.
         if (!empty($search)) {
             $headers['filters']['search'] = $search;
             $blogurl->param('search', $search);
@@ -896,7 +892,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         }
     }
 
-    // Append edit mode info
+    // Append edit mode info.
     if (!empty($action) && $action == 'add') {
 
     } else if (!empty($action) && $action == 'edit') {
index 5561050..5df39ad 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -40,7 +39,7 @@ require_once($CFG->libdir . '/filelib.php');
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class blog_entry implements renderable {
-    // Public Database fields
+    // Public Database fields.
     public $id;
     public $userid;
     public $subject;
@@ -49,7 +48,7 @@ class blog_entry implements renderable {
     public $attachment;
     public $publishstate;
 
-    // Locked Database fields (Don't touch these)
+    // Locked Database fields (Don't touch these).
     public $courseid = 0;
     public $groupid = 0;
     public $module = 'blog';
@@ -62,14 +61,13 @@ class blog_entry implements renderable {
     public $created;
     public $usermodified;
 
-    // Other class variables
+    // Other class variables.
     public $form;
     public $tags = array();
 
     /** @var StdClass Data needed to render the entry */
     public $renderable;
 
-    // Methods
     /**
      * Constructor. If given an id, will fetch the corresponding record from the DB.
      *
@@ -137,11 +135,12 @@ class blog_entry implements renderable {
             if ($externalblog = $DB->get_record('blog_external', array('id' => $this->content))) {
                 $urlparts = parse_url($externalblog->url);
                 $this->renderable->externalblogtext = get_string('retrievedfrom', 'blog') . get_string('labelsep', 'langconfig');
-                $this->renderable->externalblogtext .= html_writer::link($urlparts['scheme'] . '://'.$urlparts['host'], $externalblog->name);
+                $this->renderable->externalblogtext .= html_writer::link($urlparts['scheme'] . '://' . $urlparts['host'],
+                                                                         $externalblog->name);
             }
         }
 
-        // Retrieve associations
+        // Retrieve associations.
         $this->renderable->unassociatedentry = false;
         if (!empty($CFG->useblogassociations)) {
 
@@ -165,9 +164,11 @@ class blog_entry implements renderable {
 
                     // Course associations.
                     if ($context->contextlevel ==  CONTEXT_COURSE) {
-                        $instancename = $DB->get_field('course', 'shortname', array('id' => $context->instanceid)); //TODO: performance!!!!
+                        // TODO: performance!!!!
+                        $instancename = $DB->get_field('course', 'shortname', array('id' => $context->instanceid));
 
-                        $associations[$key]->url = $assocurl = new moodle_url('/course/view.php', array('id' => $context->instanceid));
+                        $associations[$key]->url = $assocurl = new moodle_url('/course/view.php',
+                                                                              array('id' => $context->instanceid));
                         $associations[$key]->text = $instancename;
                         $associations[$key]->icon = new pix_icon('i/course', $associations[$key]->text);
                     }
@@ -175,15 +176,17 @@ class blog_entry implements renderable {
                     // Mod associations.
                     if ($context->contextlevel ==  CONTEXT_MODULE) {
 
-                        // Getting the activity type and the activity instance id
+                        // Getting the activity type and the activity instance id.
                         $sql = 'SELECT cm.instance, m.name FROM {course_modules} cm
                                   JOIN {modules} m ON m.id = cm.module
                                  WHERE cm.id = :cmid';
                         $modinfo = $DB->get_record_sql($sql, array('cmid' => $context->instanceid));
-                        $instancename = $DB->get_field($modinfo->name, 'name', array('id' => $modinfo->instance)); //TODO: performance!!!!
+                        // TODO: performance!!!!
+                        $instancename = $DB->get_field($modinfo->name, 'name', array('id' => $modinfo->instance));
 
                         $associations[$key]->type = get_string('modulename', $modinfo->name);
-                        $associations[$key]->url = new moodle_url('/mod/' . $modinfo->name . '/view.php', array('id' => $context->instanceid));
+                        $associations[$key]->url = new moodle_url('/mod/' . $modinfo->name . '/view.php',
+                                                                  array('id' => $context->instanceid));
                         $associations[$key]->text = $instancename;
                         $associations[$key]->icon = new pix_icon('icon', $associations[$key]->text, $modinfo->name);
                     }
@@ -203,7 +206,7 @@ class blog_entry implements renderable {
      * Gets the entry attachments list
      * @return array List of blog_entry_attachment instances
      */
-    function get_attachments() {
+    public function get_attachments() {
 
         global $CFG;
 
@@ -293,7 +296,13 @@ class blog_entry implements renderable {
         }
 
         $entry = file_postupdate_standard_editor($entry, 'summary', $summaryoptions, $sitecontext, 'blog', 'post', $entry->id);
-        $entry = file_postupdate_standard_filemanager($entry, 'attachment', $attachmentoptions, $sitecontext, 'blog', 'attachment', $entry->id);
+        $entry = file_postupdate_standard_filemanager($entry,
+                                                      'attachment',
+                                                      $attachmentoptions,
+                                                      $sitecontext,
+                                                      'blog',
+                                                      'attachment',
+                                                      $entry->id);
 
         if (!empty($CFG->useblogassociations)) {
             $entry->add_associations();
@@ -427,7 +436,7 @@ class blog_entry implements renderable {
 
         if ($otags = optional_param('otags', '', PARAM_INT)) {
             foreach ($otags as $tagid) {
-                // TODO : make this use the tag name in the form
+                // TODO : make this use the tag name in the form.
                 if ($tag = tag_get('id', $tagid)) {
                     $tags[] = $tag->name;
                 }
@@ -456,11 +465,11 @@ class blog_entry implements renderable {
         $sitecontext = context_system::instance();
 
         if (has_capability('moodle/blog:manageentries', $sitecontext)) {
-            return true; // can edit any blog entry
+            return true; // Can edit any blog entry.
         }
 
         if ($this->userid == $userid && has_capability('moodle/blog:create', $sitecontext)) {
-            return true; // can edit own when having blog:create capability
+            return true; // Can edit own when having blog:create capability.
         }
 
         return false;
@@ -480,23 +489,23 @@ class blog_entry implements renderable {
         $sitecontext = context_system::instance();
 
         if (empty($CFG->enableblogs) || !has_capability('moodle/blog:view', $sitecontext)) {
-            return false; // blog system disabled or user has no blog view capability
+            return false; // Blog system disabled or user has no blog view capability.
         }
 
         if (isloggedin() && $USER->id == $targetuserid) {
-            return true; // can view own entries in any case
+            return true; // Can view own entries in any case.
         }
 
         if (has_capability('moodle/blog:manageentries', $sitecontext)) {
-            return true; // can manage all entries
+            return true; // Can manage all entries.
         }
 
-        // coming for 1 entry, make sure it's not a draft
+        // Coming for 1 entry, make sure it's not a draft.
         if ($this->publishstate == 'draft' && !has_capability('moodle/blog:viewdrafts', $sitecontext)) {
-            return false;  // can not view draft of others
+            return false;  // Can not view draft of others.
         }
 
-        // coming for 1 entry, make sure user is logged in, if not a public blog
+        // Coming for 1 entry, make sure user is logged in, if not a public blog.
         if ($this->publishstate != 'public' && !isloggedin()) {
             return false;
         }
@@ -507,7 +516,7 @@ class blog_entry implements renderable {
                 break;
 
             case BLOG_SITE_LEVEL:
-                if (isloggedin()) { // not logged in viewers forbidden
+                if (isloggedin()) { // Not logged in viewers forbidden.
                     return true;
                 }
                 return false;
@@ -533,7 +542,7 @@ class blog_entry implements renderable {
         global $CFG;
         $options = array();
 
-        // everyone gets draft access
+        // Everyone gets draft access.
         if ($CFG->bloglevel >= BLOG_USER_LEVEL) {
             $options['draft'] = get_string('publishtonoone', 'blog');
         }
@@ -577,7 +586,7 @@ class blog_listing {
      * @param array $filters An associative array of filtername => filterid
      */
     public function __construct($filters=array()) {
-        // Unset filters overridden by more specific filters
+        // Unset filters overridden by more specific filters.
         foreach ($filters as $type => $id) {
             if (!empty($type) && !empty($id)) {
                 $this->filters[$type] = blog_filter::get_instance($id, $type);
@@ -615,50 +624,53 @@ class blog_listing {
     public function get_entry_fetch_sql($count=false, $sort='lastmodified DESC', $userid = false) {
         global $DB, $USER, $CFG;
 
-        if(!$userid) {
+        if (!$userid) {
             $userid = $USER->id;
         }
 
         $allnamefields = get_all_user_name_fields(true, 'u');
         // The query used to locate blog entries is complicated.  It will be built from the following components:
-        $requiredfields = "p.*, $allnamefields, u.email";  // the SELECT clause
-        $tables = array('p' => 'post', 'u' => 'user');   // components of the FROM clause (table_id => table_name)
-        $conditions = array('u.deleted = 0', 'p.userid = u.id', '(p.module = \'blog\' OR p.module = \'blog_external\')');  // components of the WHERE clause (conjunction)
+        $requiredfields = "p.*, $allnamefields, u.email";  // The SELECT clause.
+        $tables = array('p' => 'post', 'u' => 'user');   // Components of the FROM clause (table_id => table_name).
+        // Components of the WHERE clause (conjunction).
+        $conditions = array('u.deleted = 0', 'p.userid = u.id', '(p.module = \'blog\' OR p.module = \'blog_external\')');
 
-        // build up a clause for permission constraints
+        // Build up a clause for permission constraints.
 
         $params = array();
 
-        // fix for MDL-9165, use with readuserblogs capability in a user context can read that user's private blogs
-        // admins can see all blogs regardless of publish states, as described on the help page
+        // Fix for MDL-9165, use with readuserblogs capability in a user context can read that user's private blogs.
+        // Admins can see all blogs regardless of publish states, as described on the help page.
         if (has_capability('moodle/user:readuserblogs', context_system::instance())) {
-            // don't add permission constraints
+            // Don't add permission constraints.
 
-        } else if(!empty($this->filters['user']) && has_capability('moodle/user:readuserblogs',
-                context_user::instance((empty($this->filters['user']->id) ? 0 : $this->filters['user']->id)))) {
-            // don't add permission constraints
+        } else if (!empty($this->filters['user'])
+                   && has_capability('moodle/user:readuserblogs',
+                                     context_user::instance((empty($this->filters['user']->id) ? 0 : $this->filters['user']->id)))) {
+            // Don't add permission constraints.
 
         } else {
             if (isloggedin() and !isguestuser()) {
-                $assocexists = $DB->record_exists('blog_association', array());  //dont check association records if there aren't any
+                // Dont check association records if there aren't any.
+                $assocexists = $DB->record_exists('blog_association', array());
 
-                //begin permission sql clause
+                // Begin permission sql clause.
                 $permissionsql =  '(p.userid = ? ';
                 $params[] = $userid;
 
-                if ($CFG->bloglevel >= BLOG_SITE_LEVEL) { // add permission to view site-level entries
+                if ($CFG->bloglevel >= BLOG_SITE_LEVEL) { // Add permission to view site-level entries.
                     $permissionsql .= " OR p.publishstate = 'site' ";
                 }
 
-                if ($CFG->bloglevel >= BLOG_GLOBAL_LEVEL) { // add permission to view global entries
+                if ($CFG->bloglevel >= BLOG_GLOBAL_LEVEL) { // Add permission to view global entries.
                     $permissionsql .= " OR p.publishstate = 'public' ";
                 }
 
-                $permissionsql .= ') ';   //close permissions sql clause
-            } else {  // default is access to public entries
+                $permissionsql .= ') ';   // Close permissions sql clause.
+            } else {  // Default is access to public entries.
                 $permissionsql = "p.publishstate = 'public'";
             }
-            $conditions[] = $permissionsql;  //add permission constraints
+            $conditions[] = $permissionsql;  // Add permission constraints.
         }
 
         foreach ($this->filters as $type => $blogfilter) {
@@ -667,7 +679,7 @@ class blog_listing {
             $tables = array_merge($tables, $blogfilter->tables);
         }
 
-        $tablessql = '';  // build up the FROM clause
+        $tablessql = '';  // Build up the FROM clause.
         foreach ($tables as $tablename => $table) {
             $tablessql .= ($tablessql ? ', ' : '').'{'.$table.'} '.$tablename;
         }
@@ -688,7 +700,7 @@ class blog_listing {
         global $CFG, $USER, $DB, $OUTPUT, $PAGE;
         $sitecontext = context_system::instance();
 
-        // Blog renderer
+        // Blog renderer.
         $output = $PAGE->get_renderer('blog');
 
         $page  = optional_param('blogpage', 0, PARAM_INT);
@@ -711,7 +723,7 @@ class blog_listing {
         echo $OUTPUT->render($pagingbar);
 
         if (has_capability('moodle/blog:create', $sitecontext)) {
-            //the user's blog is enabled and they are viewing their own blog
+            // The user's blog is enabled and they are viewing their own blog.
             $userid = optional_param('userid', null, PARAM_INT);
 
             if (empty($userid) || (!empty($userid) && $userid == $USER->id)) {
@@ -744,7 +756,7 @@ class blog_listing {
             foreach ($entries as $entry) {
                 $blogentry = new blog_entry(null, $entry);
 
-                // Get the required blog entry data to render it
+                // Get the required blog entry data to render it.
                 $blogentry->prepare_render();
                 echo $output->render($blogentry);
 
@@ -762,7 +774,7 @@ class blog_listing {
         }
     }
 
-    /// Find the base url from $_GET variables, for print_paging_bar
+    // Find the base url from $_GET variables, for print_paging_bar.
     public function get_baseurl() {
         $getcopy  = $_GET;
 
@@ -897,11 +909,13 @@ class blog_filter_context extends blog_filter {
             $this->type = $type;
         }
 
-        $this->availabletypes = array('site' => get_string('site'), 'course' => get_string('course'), 'module' => get_string('activity'));
+        $this->availabletypes = array('site' => get_string('site'),
+                                      'course' => get_string('course'),
+                                      'module' => get_string('activity'));
 
         switch ($this->type) {
             case 'course': // Careful of site course!
-                // Ignore course filter if blog associations are not enabled
+                // Ignore course filter if blog associations are not enabled.
                 if ($this->id != $SITE->id && !empty($CFG->useblogassociations)) {
                     $this->overrides = array('site');
                     $context = context_course::instance($this->id);
@@ -910,11 +924,11 @@ class blog_filter_context extends blog_filter {
                     $this->conditions[] = 'ba.contextid = '.$context->id;
                     break;
                 } else {
-                    // We are dealing with the site course, do not break from the current case
+                    // We are dealing with the site course, do not break from the current case.
                 }
 
             case 'site':
-                // No special constraints
+                // No special constraints.
                 break;
             case 'module':
                 if (!empty($CFG->useblogassociations)) {
@@ -961,7 +975,7 @@ class blog_filter_user extends blog_filter {
             $this->params = array($this->id);
             $this->overrides = array('group');
 
-        } elseif ($this->type == 'group') {
+        } else if ($this->type == 'group') {
             $this->overrides = array('course', 'site');
 
             $this->tables['gm'] = 'groups_members';
@@ -969,7 +983,7 @@ class blog_filter_user extends blog_filter {
             $this->conditions[] = 'gm.groupid = ?';
             $this->params[]     = $this->id;
 
-            if (!empty($CFG->useblogassociations)) {  // only show blog entries associated with this course
+            if (!empty($CFG->useblogassociations)) {  // Only show blog entries associated with this course.
                 $coursecontext     = context_course::instance($DB->get_field('groups', 'courseid', array('id' => $this->id)));
                 $this->tables['ba'] = 'blog_association';
                 $this->conditions[] = 'gm.groupid = ?';
@@ -1068,7 +1082,8 @@ class blog_entry_attachment implements renderable {
 
         $this->file = $file;
         $this->filename = $file->get_filename();
-        $this->url = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.SYSCONTEXTID.'/blog/attachment/'.$entryid.'/'.$this->filename);
+        $this->url = file_encode_url($CFG->wwwroot . '/pluginfile.php',
+                                     '/' . SYSCONTEXTID . '/blog/attachment/' . $entryid . '/' . $this->filename);
     }
 
 }
index e3d82fc..59aea44 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -66,7 +65,7 @@ if (empty($CFG->enableblogs)) {
 // The preference is site wide not blog specific. Hence user should have permissions in site level.
 require_capability('moodle/blog:view', $sitecontext);
 
-/// If data submitted, then process and store.
+// If data submitted, then process and store.
 
 $mform = new blog_preferences_form('preferences.php');
 $mform->set_data(array('pagesize' => get_user_preferences('blogpagesize')));
@@ -80,7 +79,7 @@ if (!$mform->is_cancelled() && $data = $mform->get_data()) {
     set_user_preference('blogpagesize', $pagesize);
 }
 
-if ($mform->is_cancelled()){
+if ($mform->is_cancelled()) {
     redirect($CFG->wwwroot . '/blog/index.php');
 }
 
index d5c5005..12edfed 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -26,7 +25,7 @@
  */
 
 if (!defined('MOODLE_INTERNAL')) {
-    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
+    die('Direct access to this script is forbidden.');    //  It must be included from a Moodle page.
 }
 
 require_once($CFG->libdir.'/formslib.php');
index af1724d..832d4b1 100644 (file)
@@ -63,7 +63,9 @@ class core_blog_renderer extends plugin_renderer_base {
         $o .= $this->output->container_start('topic starter header clearfix');
 
         // Title.
-        $titlelink =  html_writer::link(new moodle_url('/blog/index.php', array('entryid' => $entry->id)), format_string($entry->subject));
+        $titlelink = html_writer::link(new moodle_url('/blog/index.php',
+                                                       array('entryid' => $entry->id)),
+                                                       format_string($entry->subject));
         $o .= $this->output->container($titlelink, 'subject');
 
         // Post by.
@@ -244,9 +246,14 @@ class core_blog_renderer extends plugin_renderer_base {
             $o = html_writer::empty_tag('img', $attrs);
             $class = 'attachedimages';
         } else {
-            $image = $this->output->pix_icon(file_file_icon($attachment->file), $attachment->filename, 'moodle', array('class'=>'icon'));
+            $image = $this->output->pix_icon(file_file_icon($attachment->file),
+                                             $attachment->filename,
+                                             'moodle',
+                                             array('class' => 'icon'));
             $o = html_writer::link($attachment->url, $image);
-            $o .= format_text(html_writer::link($attachment->url, $attachment->filename), FORMAT_HTML, array('context' => $syscontext));
+            $o .= format_text(html_writer::link($attachment->url, $attachment->filename),
+                              FORMAT_HTML,
+                              array('context' => $syscontext));
             $class = 'attachments';
         }
 
index 12854d6..3f26eb0 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -97,9 +96,6 @@ function blog_rss_print_link($context, $filtertype, $filterselect=0, $tagid=0, $
 function blog_rss_add_http_header($context, $title, $filtertype, $filterselect=0, $tagid=0) {
     global $PAGE, $USER, $CFG;
 
-    //$componentname = 'blog';
-    //rss_add_http_header($context, $componentname, $filterselect, $title);
-
     if (!isloggedin()) {
         $userid = $CFG->siteguest;
     } else {
@@ -159,7 +155,7 @@ function blog_rss_get_feed($context, $args) {
 
     if ($CFG->bloglevel == BLOG_SITE_LEVEL) {
         if (isguestuser()) {
-            debugging(get_string('nopermissiontoshow','error'));
+            debugging(get_string('nopermissiontoshow', 'error'));
             return '';
         }
     }
@@ -170,7 +166,7 @@ function blog_rss_get_feed($context, $args) {
     }
 
     $type  = clean_param($args[3], PARAM_ALPHA);
-    $id = clean_param($args[4], PARAM_INT);  // could be groupid / courseid  / userid  depending on $type
+    $id = clean_param($args[4], PARAM_INT);  // Could be groupid / courseid  / userid  depending on $type.
 
     $tagid=0;
     if ($args[5] != 'rss.xml') {
@@ -183,14 +179,13 @@ function blog_rss_get_feed($context, $args) {
 
     if (file_exists($filename)) {
         if (filemtime($filename) + 3600 > time()) {
-            return $filename;   // It's already done so we return cached version
+            return $filename;   // It's already done so we return cached version.
         }
     }
 
     $courseid = $groupid = $userid = null;
     switch ($type) {
         case 'site':
-            //$siteid = $id;
             break;
         case 'course':
             $courseid = $id;
@@ -203,26 +198,26 @@ function blog_rss_get_feed($context, $args) {
             break;
     }
 
-    // Get all the entries from the database
+    // Get all the entries from the database.
     require_once($CFG->dirroot .'/blog/locallib.php');
     $blogheaders = blog_get_headers($courseid, $groupid, $userid, $tagid);
 
     $bloglisting = new blog_listing($blogheaders['filters']);
     $blogentries = $bloglisting->get_entries();
 
-    // Now generate an array of RSS items
+    // Now generate an array of RSS items.
     if ($blogentries) {
         $items = array();
-        foreach ($blogentries as $blog_entry) {
-            $item = NULL;
-            $item->author = fullname($DB->get_record('user', array('id'=>$blog_entry->userid))); // TODO: this is slow
-            $item->title = $blog_entry->subject;
-            $item->pubdate = $blog_entry->lastmodified;
-            $item->link = $CFG->wwwroot.'/blog/index.php?entryid='.$blog_entry->id;
-            $summary = file_rewrite_pluginfile_urls($blog_entry->summary, 'pluginfile.php',
-                $sitecontext->id, 'blog', 'post', $blog_entry->id);
-            $item->description = format_text($summary, $blog_entry->format);
-            if ( !empty($CFG->usetags) && ($blogtags = tag_get_tags_array('post', $blog_entry->id)) ) {
+        foreach ($blogentries as $blogentry) {
+            $item = null;
+            $item->author = fullname($DB->get_record('user', array('id' => $blogentry->userid))); // TODO: this is slow.
+            $item->title = $blogentry->subject;
+            $item->pubdate = $blogentry->lastmodified;
+            $item->link = $CFG->wwwroot.'/blog/index.php?entryid='.$blogentry->id;
+            $summary = file_rewrite_pluginfile_urls($blogentry->summary, 'pluginfile.php',
+                $sitecontext->id, 'blog', 'post', $blogentry->id);
+            $item->description = format_text($summary, $blogentry->format);
+            if ( !empty($CFG->usetags) && ($blogtags = tag_get_tags_array('post', $blogentry->id)) ) {
                 if ($blogtags) {
                     $item->tags = $blogtags;
                 }
@@ -230,12 +225,12 @@ function blog_rss_get_feed($context, $args) {
             }
             $items[] = $item;
         }
-        $articles = rss_add_items($items);   /// Change structure to XML
+        $articles = rss_add_items($items);   // Change structure to XML.
     } else {
         $articles = '';
     }
 
-/// Get header and footer information
+    // Get header and footer information.
 
     switch ($type) {
         case 'user':
@@ -250,7 +245,7 @@ function blog_rss_get_feed($context, $args) {
             break;
         case 'group':
             $group = groups_get_group($id);
-            $info = $group->name; //TODO: $DB->get_field('groups', 'name', array('id'=>$id))
+            $info = $group->name; // TODO: $DB->get_field('groups', 'name', array('id'=>$id)).
             break;
         default:
             $info = '';
@@ -261,18 +256,18 @@ function blog_rss_get_feed($context, $args) {
         $info .= ': '.$DB->get_field('tags', 'text', array('id'=>$tagid));
     }
 
-    $header = rss_standard_header(get_string($type.'blog','blog', $info),
+    $header = rss_standard_header(get_string($type.'blog', 'blog', $info),
                                   $CFG->wwwroot.'/blog/index.php',
-                                  get_string('intro','blog'));
+                                  get_string('intro', 'blog'));
 
     $footer = rss_standard_footer();
 
     // Save the XML contents to file.
     $rssdata = $header.$articles.$footer;
-    if (blog_rss_save_file($type,$id,$tagid,$rssdata)) {
+    if (blog_rss_save_file($type, $id, $tagid, $rssdata)) {
         return $filename;
     } else {
-        return false;   // Couldn't find it or make it
+        return false;   // Couldn't find it or make it.
     }
 }
 
@@ -308,12 +303,12 @@ function blog_rss_save_file($type, $id, $tagid=0, $contents='') {
 
     $status = true;
 
-    //blog creates some additional dirs within the rss cache so make sure they all exist
+    // Blog creates some additional dirs within the rss cache so make sure they all exist.
     make_cache_directory('rss/blog');
     make_cache_directory('rss/blog/'.$type);
 
     $filename = blog_rss_file_name($type, $id, $tagid);
-    $expandfilename = false; //we're supplying a full file path
+    $expandfilename = false; // We are supplying a full file path.
     $status = rss_save_file('blog', $filename, $contents, $expandfilename);
 
     return $status;
index 2db2265..06b1f07 100644 (file)
@@ -32,7 +32,7 @@ require_once($CFG->dirroot . '/blog/lib.php');
  */
 class core_bloglib_testcase extends advanced_testcase {
 
-    private $courseid; // To store important ids to be used in tests
+    private $courseid;
     private $cmid;
     private $groupid;
     private $userid;
@@ -45,22 +45,22 @@ class core_bloglib_testcase extends advanced_testcase {
 
         $this->resetAfterTest();
 
-        // Create default course
+        // Create default course.
         $course = $this->getDataGenerator()->create_course(array('category'=>1, 'shortname'=>'ANON'));
         $this->assertNotEmpty($course);
         $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
         $this->assertNotEmpty($page);
 
-        // Create default group
+        // Create default group.
         $group = new stdClass();
         $group->courseid = $course->id;
         $group->name = 'ANON';
         $group->id = $DB->insert_record('groups', $group);
 
-        // Create default user
+        // Create default user.
         $user = $this->getDataGenerator()->create_user(array('username'=>'testuser', 'firstname'=>'Jimmy', 'lastname'=>'Kinnon'));
 
-        // Create default tag
+        // Create default tag.
         $tag = new stdClass();
         $tag->userid = $user->id;
         $tag->name = 'testtagname';
@@ -68,14 +68,14 @@ class core_bloglib_testcase extends advanced_testcase {
         $tag->tagtype = 'official';
         $tag->id = $DB->insert_record('tag', $tag);
 
-        // Create default post
+        // Create default post.
         $post = new stdClass();
         $post->userid = $user->id;
         $post->groupid = $group->id;
         $post->content = 'test post content text';
         $post->id = $DB->insert_record('post', $post);
 
-        // Grab important ids
+        // Grab important ids.
         $this->courseid = $course->id;
         $this->cmid = $page->cmid;
         $this->groupid  = $group->id;
@@ -88,7 +88,7 @@ class core_bloglib_testcase extends advanced_testcase {
     public function test_overrides() {
         global $SITE;
 
-        // Try all the filters at once: Only the entry filter is active
+        // Try all the filters at once: Only the entry filter is active.
         $filters = array('site' => $SITE->id, 'course' => $this->courseid, 'module' => $this->cmid,
             'group' => $this->groupid, 'user' => $this->userid, 'tag' => $this->tagid, 'entry' => $this->postid);
         $blog_listing = new blog_listing($filters);
@@ -100,7 +100,7 @@ class core_bloglib_testcase extends advanced_testcase {
         $this->assertFalse(array_key_exists('tag', $blog_listing->filters));
         $this->assertTrue(array_key_exists('entry', $blog_listing->filters));
 
-        // Again, but without the entry filter: This time, the tag, user and module filters are active
+        // Again, but without the entry filter: This time, the tag, user and module filters are active.
         $filters = array('site' => $SITE->id, 'course' => $this->courseid, 'module' => $this->cmid,
             'group' => $this->groupid, 'user' => $this->userid, 'tag' => $this->postid);
         $blog_listing = new blog_listing($filters);
@@ -111,7 +111,7 @@ class core_bloglib_testcase extends advanced_testcase {
         $this->assertTrue(array_key_exists('user', $blog_listing->filters));
         $this->assertTrue(array_key_exists('tag', $blog_listing->filters));
 
-        // We should get the same result by removing the 3 inactive filters: site, course and group:
+        // We should get the same result by removing the 3 inactive filters: site, course and group.
         $filters = array('module' => $this->cmid, 'user' => $this->userid, 'tag' => $this->tagid);
         $blog_listing = new blog_listing($filters);
         $this->assertFalse(array_key_exists('site', $blog_listing->filters));
@@ -128,26 +128,26 @@ class core_bloglib_testcase extends advanced_testcase {
 
     public function test_blog_get_headers_case_1() {
         global $CFG, $PAGE, $OUTPUT;
-        $blog_headers = blog_get_headers();
-        $this->assertEquals($blog_headers['heading'], get_string('siteblog', 'blog', 'phpunit'));
+        $blogheaders = blog_get_headers();
+        $this->assertEquals($blogheaders['heading'], get_string('siteblog', 'blog', 'phpunit'));
     }
 
     public function test_blog_get_headers_case_6() {
         global $CFG, $PAGE, $OUTPUT;
-        $blog_headers = blog_get_headers($this->courseid, NULL, $this->userid);
-        $this->assertNotEquals($blog_headers['heading'], '');
+        $blogheaders = blog_get_headers($this->courseid, null, $this->userid);
+        $this->assertNotEquals($blogheaders['heading'], '');
     }
 
     public function test_blog_get_headers_case_7() {
         global $CFG, $PAGE, $OUTPUT;
-        $blog_headers = blog_get_headers(NULL, $this->groupid);
-        $this->assertNotEquals($blog_headers['heading'], '');
+        $blogheaders = blog_get_headers(null, $this->groupid);
+        $this->assertNotEquals($blogheaders['heading'], '');
     }
 
     public function test_blog_get_headers_case_10() {
         global $CFG, $PAGE, $OUTPUT;
-        $blog_headers = blog_get_headers($this->courseid);
-        $this->assertNotEquals($blog_headers['heading'], '');
+        $blogheaders = blog_get_headers($this->courseid);
+        $this->assertNotEquals($blogheaders['heading'], '');
     }
 
     /**
index 69a8924..6a1bdf9 100644 (file)
@@ -120,7 +120,7 @@ class event_form extends moodleform {
         $group[] =& $mform->createElement('radio', 'duration', null, get_string('durationuntil', 'calendar'), 1);
         $group[] =& $mform->createElement('date_time_selector', 'timedurationuntil', '');
         $group[] =& $mform->createElement('radio', 'duration', null, get_string('durationminutes', 'calendar'), 2);
-        $group[] =& $mform->createElement('text', 'timedurationminutes', null);
+        $group[] =& $mform->createElement('text', 'timedurationminutes', get_string('durationminutes', 'calendar'));
 
         $mform->addGroup($group, 'durationgroup', '', '<br />', false);
 
index c3304fa..dcedc54 100644 (file)
@@ -3201,10 +3201,10 @@ function calendar_cron() {
         mtrace("Updating calendar subscription {$sub->name} in course {$sub->courseid}");
         try {
             $log = calendar_update_subscription_events($sub->id);
+            mtrace(trim(strip_tags($log)));
         } catch (moodle_exception $ex) {
-
+            mtrace('Error updating calendar subscription: ' . $ex->getMessage());
         }
-        mtrace(trim(strip_tags($log)));
     }
 
     mtrace('Finished updating calendar subscriptions.');
index c405b96..2a61b5e 100644 (file)
@@ -35,9 +35,11 @@ require_once($CFG->dirroot . '/calendar/lib.php');
  */
 class core_calendar_lib_testcase extends advanced_testcase {
 
-    public function test_calendar_get_course_cached() {
+    protected function setUp() {
         $this->resetAfterTest(true);
+    }
 
+    public function test_calendar_get_course_cached() {
         // Setup some test courses.
         $course1 = $this->getDataGenerator()->create_course();
         $course2 = $this->getDataGenerator()->create_course();
@@ -68,4 +70,50 @@ class core_calendar_lib_testcase extends advanced_testcase {
         $this->assertEquals($course3->shortname, $cachedcourse3->shortname);
         $this->assertEquals($course3->fullname, $cachedcourse3->fullname);
     }
+
+    /**
+     * Test calendar cron with a working subscription URL.
+     */
+    public function test_calendar_cron_working_url() {
+        global $CFG;
+        require_once($CFG->dirroot . '/lib/cronlib.php');
+
+        // Moodle ICal URL (moodle.org events).
+        $presetwhat = 'all';
+        $presettime = 'recentupcoming';
+        $userid = 1;
+        $authtoken = 'a8bcfee2fb868a05357f650bd65dc0699b026524';
+        $subscriptionurl = 'https://moodle.org/calendar/export_execute.php'
+                . '?preset_what='.$presetwhat.'&preset_time='.$presettime.'&userid='.$userid.'&authtoken='.$authtoken;
+
+        $subscription = new stdClass();
+        $subscription->eventtype = 'site';
+        $subscription->name = 'test';
+        $subscription->url = $subscriptionurl;
+        $subscription->pollinterval = 86400;
+        $subscription->lastupdated = 0;
+        calendar_add_subscription($subscription);
+
+        $this->expectOutputRegex('/Events imported: .* Events updated:/');
+        calendar_cron();
+    }
+
+    /**
+     * Test calendar cron with a broken subscription URL.
+     */
+    public function test_calendar_cron_broken_url() {
+        global $CFG;
+        require_once($CFG->dirroot . '/lib/cronlib.php');
+
+        $subscription = new stdClass();
+        $subscription->eventtype = 'site';
+        $subscription->name = 'test';
+        $subscription->url = 'brokenurl';
+        $subscription->pollinterval = 86400;
+        $subscription->lastupdated = 0;
+        calendar_add_subscription($subscription);
+
+        $this->expectOutputRegex('/Error updating calendar subscription: The given iCal URL is invalid/');
+        calendar_cron();
+    }
 }
index 688e304..530d507 100644 (file)
@@ -1203,6 +1203,51 @@ class core_course_management_renderer extends plugin_renderer_base {
         return html_writer::span(join('', $actions), 'course-item-actions item-actions');
     }
 
+    /**
+     * Renders html to display a course search form
+     *
+     * @param string $value default value to populate the search field
+     * @param string $format display format - 'plain' (default), 'short' or 'navbar'
+     * @return string
+     */
+    public function course_search_form($value = '', $format = 'plain') {
+        static $count = 0;
+        $formid = 'coursesearch';
+        if ((++$count) > 1) {
+            $formid .= $count;
+        }
+
+        switch ($format) {
+            case 'navbar' :
+                $formid = 'coursesearchnavbar';
+                $inputid = 'navsearchbox';
+                $inputsize = 20;
+                break;
+            case 'short' :
+                $inputid = 'shortsearchbox';
+                $inputsize = 12;
+                break;
+            default :
+                $inputid = 'coursesearchbox';
+                $inputsize = 30;
+        }
+
+        $strsearchcourses = get_string("searchcourses");
+        $searchurl = new moodle_url('/course/management.php');
+
+        $output = html_writer::start_tag('form', array('id' => $formid, 'action' => $searchurl, 'method' => 'get'));
+        $output .= html_writer::start_tag('fieldset', array('class' => 'coursesearchbox invisiblefieldset'));
+        $output .= html_writer::tag('label', $strsearchcourses.': ', array('for' => $inputid));
+        $output .= html_writer::empty_tag('input', array('type' => 'text', 'id' => $inputid,
+            'size' => $inputsize, 'name' => 'search', 'value' => s($value)));
+        $output .= html_writer::empty_tag('input', array('type' => 'submit',
+            'value' => get_string('go')));
+        $output .= html_writer::end_tag('fieldset');
+        $output .= html_writer::end_tag('form');
+
+        return $output;
+    }
+
     /**
      * Creates access hidden skip to links for the displayed sections.
      *
index c48158d..b87b74f 100644 (file)
@@ -508,4 +508,6 @@ echo $renderer->grid_end();
 
 // End of the management form.
 echo $renderer->management_form_end();
+echo $renderer->course_search_form($search);
+
 echo $renderer->footer();
index 6db0851..f6d2d9b 100644 (file)
@@ -270,13 +270,16 @@ class enrol_imsenterprise_plugin extends enrol_plugin {
      * @param string $tagcontents The raw contents of the XML element
      */
     protected function process_group_tag($tagcontents) {
-        global $DB;
+        global $DB, $CFG;
 
         // Get configs.
         $truncatecoursecodes    = $this->get_config('truncatecoursecodes');
         $createnewcourses       = $this->get_config('createnewcourses');
         $createnewcategories    = $this->get_config('createnewcategories');
 
+        if ($createnewcourses) {
+            require_once("$CFG->dirroot/course/lib.php");
+        }
         // Process tag contents.
         $group = new stdClass();
         if (preg_match('{<sourcedid>.*?<id>(.+?)</id>.*?</sourcedid>}is', $tagcontents, $matches)) {
index 7623b14..b497034 100644 (file)
@@ -602,13 +602,13 @@ class core_files_renderer extends plugin_renderer_base {
                     <div class="fp-tb-message"></div>
                 </div>
                 <div class="fp-viewbar">
-                    <a title="'. get_string('displayicons', 'repository') .'" class="fp-vb-icons" href="#">
+                    <a role="button" 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="#">
+                    <a role="button" 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="#">
+                    <a role="button" title="'. get_string('displaytree', 'repository') .'" class="fp-vb-tree" href="#">
                         <img alt="" src="'. $this->pix_url('fp/view_tree_active', 'theme') .'" />
                     </a>
                 </div>
index 0f46959..d9ce6f7 100644 (file)
@@ -74,11 +74,12 @@ class filter_activitynames extends moodle_text_filter {
                             'name' => $cm->name,
                             'url' => $cm->url,
                             'id' => $cm->id,
-                            'namelen' => strlen($cm->name),
+                            'namelen' => -strlen($cm->name), // Negative value for reverse sorting.
                         );
                     }
                 }
-                core_collator::asort_objects_by_property($sortedactivities, 'namelen', SORT_NUMERIC);
+                // Sort activities by the length of the activity name in reverse order.
+                core_collator::asort_objects_by_property($sortedactivities, 'namelen', core_collator::SORT_NUMERIC);
 
                 foreach ($sortedactivities as $cm) {
                     $title = s(trim(strip_tags($cm->name)));
index 0a4b562..6c957c8 100644 (file)
@@ -85,7 +85,7 @@ if ($editform->is_cancelled()) {
         default:
             print_error('unknoworder');
     }
-    $users = groups_get_potential_members($data->courseid, $data->roleid, $data->cohortid, $orderby);
+    $users = groups_get_potential_members($data->courseid, $data->roleid, $data->cohortid, $orderby, !empty($data->notingroup));
     $usercnt = count($users);
 
     if ($data->allocateby == 'random') {
index c62c390..d874911 100644 (file)
@@ -110,6 +110,8 @@ class autogroup_form extends moodleform {
         $mform->addElement('checkbox', 'nosmallgroups', get_string('nosmallgroups', 'group'));
         $mform->disabledIf('nosmallgroups', 'groupby', 'noteq', 'members');
 
+        $mform->addElement('checkbox', 'notingroup', get_string('notingroup', 'group'));
+
         $mform->addElement('header', 'groupinghdr', get_string('grouping', 'group'));
 
         $options = array('0' => get_string('nogrouping', 'group'),
index 970ce78..7d44a43 100644 (file)
@@ -709,23 +709,42 @@ function groups_get_possible_roles($context) {
  * @param int $roleid The role to select users from
  * @param int $cohortid restrict to cohort id
  * @param string $orderby The column to sort users by
+ * @param int $notingroup restrict to users not in existing groups
  * @return array An array of the users
  */
-function groups_get_potential_members($courseid, $roleid = null, $cohortid = null, $orderby = 'lastname ASC, firstname ASC') {
+function groups_get_potential_members($courseid, $roleid = null, $cohortid = null,
+                                      $orderby = 'lastname ASC, firstname ASC',
+                                      $notingroup = null) {
     global $DB;
 
     $context = context_course::instance($courseid);
 
     list($esql, $params) = get_enrolled_sql($context);
 
+    $notingroupsql = "";
+    if ($notingroup) {
+        // We want to eliminate users that are already associated with a course group.
+        $notingroupsql = "u.id NOT IN (SELECT userid
+                                         FROM {groups_members}
+                                        WHERE groupid IN (SELECT id
+                                                            FROM {groups}
+                                                           WHERE courseid = :courseid))";
+        $params['courseid'] = $courseid;
+    }
+
     if ($roleid) {
         // We are looking for all users with this role assigned in this context or higher.
-        list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'relatedctx');
+        list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($context->get_parent_context_ids(true),
+                                                                       SQL_PARAMS_NAMED,
+                                                                       'relatedctx');
 
         $params = array_merge($params, $relatedctxparams, array('roleid' => $roleid));
         $where = "WHERE u.id IN (SELECT userid
                                    FROM {role_assignments}
                                   WHERE roleid = :roleid AND contextid $relatedctxsql)";
+        $where .= $notingroup ? "AND $notingroupsql" : "";
+    } else if ($notingroup) {
+        $where = "WHERE $notingroupsql";
     } else {
         $where = "";
     }
index a49d13f..ee7f6b0 100644 (file)
@@ -84,3 +84,28 @@ Feature: Automatic creation of groups
     And I should see "Group B" in the ".generaltable" "css_element"
     And I should see "5" in the "Group A" "table_row"
     And I should see "5" in the "Group B" "table_row"
+
+  @javascript
+  Scenario: Split automatically the course users in groups that are not in groups
+    Given I press "Cancel"
+    And I press "Create group"
+    And I set the following fields to these values:
+      | Group name | Group 1 |
+    And I press "Save changes"
+    And I press "Create group"
+    And I set the following fields to these values:
+      | Group name | Group 2 |
+    And I press "Save changes"
+    When I add "Student 0" user to "Group 1" group members
+    And I add "Student 1" user to "Group 1" group members
+    And I add "Student 2" user to "Group 2" group members
+    And I add "Student 3" user to "Group 2" group members
+    And I press "Auto-create groups"
+    And I expand all fieldsets
+    And I set the field "Auto create based on" to "Number of groups"
+    And I set the field "Group/member count" to "2"
+    And I set the field "Grouping of auto-created groups" to "No grouping"
+    And I set the field "Ignore users in groups" to "1"
+    And I press "Submit"
+    And the "groups" select box should contain "Group A (3)"
+    And the "groups" select box should contain "Group B (3)"
\ No newline at end of file
diff --git a/install/lang/af/moodle.php b/install/lang/af/moodle.php
new file mode 100644 (file)
index 0000000..e9fb8fd
--- /dev/null
@@ -0,0 +1,33 @@
+<?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/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['language'] = 'Taal';
index b9211b2..d6a74dc 100644 (file)
@@ -34,8 +34,8 @@ $string['admindirname'] = 'Каталог администратора';
 $string['availablelangs'] = 'Доступные языковые пакеты';
 $string['chooselanguagehead'] = 'Выберите язык';
 $string['chooselanguagesub'] = 'Сейчас необходимо выбрать язык ТОЛЬКО для сообщений во время установки. Язык сайта и пользовательских интерфейсов можно будет указать далее в процессе установки.';
-$string['clialreadyconfigured'] = 'Файл config.php уже существует. Если Вы хотите установить этот сайт, используйте admin/cli/install_database.php.';
-$string['clialreadyinstalled'] = 'Файл config.php уже существует. Если Вы хотите обновить сайт, то используйте скрипт admin/cli/upgrade.php.';
+$string['clialreadyconfigured'] = 'Файл config.php уже существует. Если Вы хотите установить Moodle на этот сайт, используйте admin/cli/install_database.php.';
+$string['clialreadyinstalled'] = 'Файл config.php уже существует. Если Вы хотите обновить сайт Moodle, то используйте скрипт admin/cli/upgrade.php.';
 $string['cliinstallheader'] = 'Программа установки Moodle {$a} в режиме командной строки';
 $string['databasehost'] = 'Сервер баз данных';
 $string['databasename'] = 'Название базы данных';
index eaaccaf..0d61dab 100644 (file)
@@ -1124,6 +1124,7 @@ $string['useexternalyui'] = 'Use online YUI libraries';
 $string['user'] = 'User';
 $string['userbulk'] = 'Bulk user actions';
 $string['userlist'] = 'Browse list of users';
+$string['userdefaultpreferences'] = 'User default preferences';
 $string['userpreference'] = 'User preference';
 $string['userpolicies'] = 'User policies';
 $string['users'] = 'Users';
index ac1316a..f640d22 100644 (file)
@@ -157,6 +157,7 @@ $string['nogroups'] = 'There are no groups set up in this course yet';
 $string['nogroupsassigned'] = 'No groups assigned';
 $string['nopermissionforcreation'] = 'Can\'t create group "{$a}" as you don\'t have the required permissions';
 $string['nosmallgroups'] = 'Prevent last small group';
+$string['notingroup'] = 'Ignore users in groups';
 $string['notingrouping'] = '[Not in a grouping]';
 $string['nousersinrole'] = 'There are no suitable users in the selected role';
 $string['number'] = 'Group/member count';
index 2b46997..c74e820 100644 (file)
@@ -1848,6 +1848,7 @@ $string['trackforumsyes'] = 'Yes: highlight new posts for me';
 $string['trysearching'] = 'Try searching instead.';
 $string['turneditingoff'] = 'Turn editing off';
 $string['turneditingon'] = 'Turn editing on';
+$string['unauthorisedlogin'] = 'The user account "{$a}" is not available on this site';
 $string['undecided'] = 'Undecided';
 $string['unfinished'] = 'Unfinished';
 $string['unknowncategory'] = 'Unknown category';
index 6740fe2..50470a8 100644 (file)
@@ -76,6 +76,8 @@ define('AUTH_LOGIN_FAILED', 3);
 /** Can not login because user is locked out. */
 define('AUTH_LOGIN_LOCKOUT', 4);
 
+/** Can not login becauser user is not authorised. */
+define('AUTH_LOGIN_UNAUTHORISED', 5);
 
 /**
  * Abstract authentication plugin.
index 17fd3bb..2c85687 100644 (file)
@@ -43,7 +43,7 @@ class recent_activity_viewed extends base {
      */
     protected function init() {
         $this->data['crud'] = 'r';
-        $this->data['edulevel'] = self::LEVEL_OTHER;
+        $this->data['edulevel'] = self::LEVEL_PARTICIPATING;
     }
 
     /**
index 916b92b..30ebc73 100644 (file)
@@ -64,6 +64,14 @@ abstract class adhoc_task extends task_base {
         $this->customdata = json_encode($customdata);
     }
 
+    /**
+     * Alternate setter for $customdata. Expects the data as a json_encoded string.
+     * @param string $customdata json_encoded string
+     */
+    public function set_custom_data_as_string($customdata) {
+        $this->customdata = $customdata;
+    }
+
     /**
      * Getter for $customdata.
      * @return mixed (anything that can be handled by json_decode).
@@ -72,4 +80,13 @@ abstract class adhoc_task extends task_base {
         return json_decode($this->customdata);
     }
 
+    /**
+     * Alternate getter for $customdata.
+     * @return string this is the raw json encoded version.
+     */
+    public function get_custom_data_as_string() {
+        return $this->customdata;
+    }
+
+
 }
index be60ee2..e2ec497 100644 (file)
@@ -220,7 +220,7 @@ class manager {
         $record->blocking = $task->is_blocking();
         $record->nextruntime = $task->get_next_run_time();
         $record->faildelay = $task->get_fail_delay();
-        $record->customdata = $task->get_custom_data();
+        $record->customdata = $task->get_custom_data_as_string();
 
         return $record;
     }
@@ -254,7 +254,7 @@ class manager {
             $task->set_fail_delay($record->faildelay);
         }
         if (isset($record->customdata)) {
-            $task->set_custom_data($record->customdata);
+            $task->set_custom_data_as_string($record->customdata);
         }
 
         return $task;
index 3ff0c28..2e83745 100644 (file)
@@ -477,9 +477,12 @@ class completion_info {
     /**
      * Get incomplete course completion criteria
      *
+     * @deprecated since Moodle 2.8 MDL-46290.
+     * @todo MDL-46294 This will be deleted in Moodle 3.0.
      * @return array
      */
     public function get_incomplete_criteria() {
+        debugging('completion_info->get_incomplete_criteria() is deprecated.', DEBUG_DEVELOPER);
         $incomplete = array();
 
         foreach ($this->get_criteria() as $criteria) {
index a2c7cd7..166e5a3 100644 (file)
@@ -111,7 +111,7 @@ M.form_filemanager.init = function(Y, options) {
             var labelid = 'fm-dialog-label_'+ this.selectnode.get('id');
             this.selectui = new M.core.dialogue({
                 draggable    : true,
-                headerContent: '<span id="' + labelid +'">' + M.str.moodle.edit + '</span>',
+                headerContent: '<h3 id="' + labelid +'">' + M.str.moodle.edit + '</h3>',
                 bodyContent  : this.selectnode,
                 centered     : true,
                 width        : '480px',
index 66e4e97..b949b74 100644 (file)
@@ -41,6 +41,22 @@ class HTMLPurifier_URIScheme_rtsp extends HTMLPurifier_URIScheme {
 }
 
 
+/**
+ * Validates RTMP defined by Adobe
+ */
+class HTMLPurifier_URIScheme_rtmp extends HTMLPurifier_URIScheme {
+
+    public $browsable = false;
+    public $hierarchical = true;
+
+    public function doValidate(&$uri, $config, $context) {
+        $uri->userinfo = null;
+        return true;
+    }
+
+}
+
+
 /**
  * Validates IRC defined by IETF Draft
  */
index 17c85d9..6018d1a 100644 (file)
@@ -1329,6 +1329,8 @@ function html_is_blank($string) {
  *
  * A NULL value will delete the entry.
  *
+ * NOTE: this function is called from lib/db/upgrade.php
+ *
  * @param string $name the key to set
  * @param string $value the value to set (without magic quotes)
  * @param string $plugin (optional) the plugin scope, default null
@@ -1399,6 +1401,8 @@ function set_config($name, $value, $plugin=null) {
  * If called with 2 parameters it will return a string single
  * value or false if the value is not found.
  *
+ * NOTE: this function is called from lib/db/upgrade.php
+ *
  * @static string|false $siteidentifier The site identifier is not cached. We use this static cache so
  *     that we need only fetch it once per request.
  * @param string $plugin full component name
@@ -1485,6 +1489,8 @@ function get_config($plugin, $name = null) {
 /**
  * Removes a key from global configuration.
  *
+ * NOTE: this function is called from lib/db/upgrade.php
+ *
  * @param string $name the key to set
  * @param string $plugin (optional) the plugin scope
  * @return boolean whether the operation succeeded.
@@ -4426,20 +4432,6 @@ function authenticate_user_login($username, $password, $ignorelockout=false, &$f
             return false;
         }
 
-        // Do not try to authenticate non-existent accounts when user creation is disabled.
-        if (!empty($CFG->authpreventaccountcreation)) {
-            $failurereason = AUTH_LOGIN_NOUSER;
-
-            // Trigger login failed event.
-            $event = \core\event\user_login_failed::create(array('other' => array('username' => $username,
-                    'reason' => $failurereason)));
-            $event->trigger();
-
-            error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Unknown user, can not create new accounts:  $username  ".
-                    $_SERVER['HTTP_USER_AGENT']);
-            return false;
-        }
-
         // User does not exist.
         $auths = $authsenabled;
         $user = new stdClass();
@@ -4492,8 +4484,21 @@ function authenticate_user_login($username, $password, $ignorelockout=false, &$f
                 $user = update_user_record_by_id($user->id);
             }
         } else {
-            // Create account, we verified above that user creation is allowed.
-            $user = create_user_record($username, $password, $auth);
+            // The user is authenticated but user creation may be disabled.
+            if (!empty($CFG->authpreventaccountcreation)) {
+                $failurereason = AUTH_LOGIN_UNAUTHORISED;
+
+                // Trigger login failed event.
+                $event = \core\event\user_login_failed::create(array('other' => array('username' => $username,
+                        'reason' => $failurereason)));
+                $event->trigger();
+
+                error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Unknown user, can not create new accounts:  $username  ".
+                        $_SERVER['HTTP_USER_AGENT']);
+                return false;
+            } else {
+                $user = create_user_record($username, $password, $auth);
+            }
         }
 
         $authplugin->sync_roles($user);
@@ -8752,17 +8757,19 @@ function message_popup_window() {
 
     // A quick query to check whether the user has new messages.
     $messagecount = $DB->count_records('message', array('useridto' => $USER->id));
-    if ($messagecount<1) {
+    if ($messagecount < 1) {
         return;
     }
 
-    // Got unread messages so now do another query that joins with the user table.
+    // There are unread messages so now do a more complex but slower query.
     $namefields = get_all_user_name_fields(true, 'u');
-    $messagesql = "SELECT m.id, m.smallmessage, m.fullmessageformat, m.notification, $namefields
+    $messagesql = "SELECT m.id, m.smallmessage, m.fullmessageformat, m.notification, m.useridto, m.useridfrom, $namefields, c.blocked
                      FROM {message} m
                      JOIN {message_working} mw ON m.id=mw.unreadmessageid
                      JOIN {message_processors} p ON mw.processorid=p.id
                      JOIN {user} u ON m.useridfrom=u.id
+                     LEFT JOIN {message_contacts} c ON c.contactid = m.useridfrom
+                                                   AND c.userid = m.useridto
                     WHERE m.useridto = :userid
                       AND p.name='popup'";
 
@@ -8775,10 +8782,18 @@ function message_popup_window() {
 
     $messageusers = $DB->get_records_sql($messagesql, array('userid' => $USER->id, 'lastpopuptime' => $USER->message_lastpopup));
 
-    // If we have new messages to notify the user about.
-    if (!empty($messageusers)) {
+    $validmessages = 0;
+    foreach($messageusers as $message) {
+        if ($message->blocked) {
+            // Message is from a user who has since been blocked so just mark it read.
+            message_mark_message_read($message, time());
+        } else {
+            $validmessages++;
+        }
+    }
 
-        $strmessages = get_string('unreadnewmessages', 'message', count($messageusers));
+    if ($validmessages > 0) {
+        $strmessages = get_string('unreadnewmessages', 'message', $validmessages);
         $strgomessage = get_string('gotomessages', 'message');
         $strstaymessage = get_string('ignore', 'admin');
 
index 67e44be..6a15a68 100644 (file)
@@ -219,7 +219,23 @@ EOD;
         }
 
         if (!isset($record['maildisplay'])) {
-            $record['maildisplay'] = 1;
+            $record['maildisplay'] = $CFG->defaultpreference_maildisplay;
+        }
+
+        if (!isset($record['mailformat'])) {
+            $record['mailformat'] = $CFG->defaultpreference_mailformat;
+        }
+
+        if (!isset($record['maildigest'])) {
+            $record['maildigest'] = $CFG->defaultpreference_maildigest;
+        }
+
+        if (!isset($record['autosubscribe'])) {
+            $record['autosubscribe'] = $CFG->defaultpreference_autosubscribe;
+        }
+
+        if (!isset($record['trackforums'])) {
+            $record['trackforums'] = $CFG->defaultpreference_trackforums;
         }
 
         if (!isset($record['deleted'])) {
index 88a1644..51d22c8 100644 (file)
@@ -295,6 +295,9 @@ class core_htmlpurifier_testcase extends basic_testcase {
         $text = '<a href="rtsp://www.example.com/movie.mov">link</a>';
         $this->assertSame($text, purify_html($text));
 
+        $text = '<a href="rtmp://www.example.com/video.f4v">link</a>';
+        $this->assertSame($text, purify_html($text));
+
         $text = '<a href="teamspeak://speak.example.com/?par=val?par2=val2">link</a>';
         $this->assertSame($text, purify_html($text));
 
index 04a7c18..9e067cf 100644 (file)
@@ -8,7 +8,11 @@ information provided here is intended especially for developers.
   If you have a renderable class named like "blah_renderable" and have a method on a renderer named "render_blah_renderable"
   you will need to change the name of your render method to "render_blah" instead, as renderable at the end is no longer accepted.
 
+DEPRECATIONS:
+* completion_info->get_incomplete_criteria() is deprecated and will be removed in Moodle 3.0.
+
 === 2.6.4 / 2.7.1 ===
+
 * setnew_password_and_mail() and update_internal_user_password() will trigger
   \core\event\user_password_updated. Previously they used to generate
   \core\event\user_updated event.
index 55ae5f7..c082abb 100644 (file)
@@ -1680,6 +1680,7 @@ function purify_html($text, $options = array()) {
             'nntp' => true,
             'news' => true,
             'rtsp' => true,
+            'rtmp' => true,
             'teamspeak' => true,
             'gopher' => true,
             'mms' => true,
index a4e29fc..587eb0e 100644 (file)
@@ -137,7 +137,7 @@ if ($frm and isset($frm->username)) {                             // Login WITH
         $frm = false;
     } else {
         if (empty($errormsg)) {
-            $user = authenticate_user_login($frm->username, $frm->password);
+            $user = authenticate_user_login($frm->username, $frm->password, false, $errorcode);
         }
     }
 
@@ -233,8 +233,12 @@ if ($frm and isset($frm->username)) {                             // Login WITH
 
     } else {
         if (empty($errormsg)) {
-            $errormsg = get_string("invalidlogin");
-            $errorcode = 3;
+            if ($errorcode == AUTH_LOGIN_UNAUTHORISED) {
+                $errormsg = get_string("unauthorisedlogin", "", $frm->username);
+            } else {
+                $errormsg = get_string("invalidlogin");
+                $errorcode = 3;
+            }
         }
     }
 }
index bae2d7c..7f212c3 100644 (file)
@@ -43,7 +43,6 @@ if (empty($CFG->authloginviaemail)) {
             <div class="form-label"><label for="password"><?php print_string("password") ?></label></div>
             <div class="form-input">
               <input type="password" name="password" id="password" size="15" value="" <?php echo $autocomplete; ?> />
-              <input type="submit" id="loginbtn" value="<?php print_string("login") ?>" />
             </div>
           </div>
             <div class="clearer"><!-- --></div>
@@ -54,6 +53,7 @@ if (empty($CFG->authloginviaemail)) {
               </div>
               <?php } ?>
           <div class="clearer"><!-- --></div>
+          <input type="submit" id="loginbtn" value="<?php print_string("login") ?>" />
           <div class="forgetpass"><a href="forgot_password.php"><?php print_string("forgotten") ?></a></div>
         </form>
         <div class="desc">
index a3bb7cb..85e4a9e 100644 (file)
@@ -2352,7 +2352,7 @@ function message_move_userfrom_unread2read($userid) {
  * @param int $fromuserid the id of the message sender
  * @return void
  */
-function message_mark_messages_read($touserid, $fromuserid){
+function message_mark_messages_read($touserid, $fromuserid) {
     global $DB;
 
     $sql = 'SELECT m.* FROM {message} m WHERE m.useridto=:useridto AND m.useridfrom=:useridfrom';
index 5506a6b..115a04e 100644 (file)
@@ -294,9 +294,6 @@ class assign_grading_table extends table_sql implements renderable {
         if ($assignment->get_instance()->teamsubmission) {
             $columns[] = 'team';
             $headers[] = get_string('submissionteam', 'assign');
-
-            $columns[] = 'teamstatus';
-            $headers[] = get_string('teamsubmissionstatus', 'assign');
         }
         // Allocated marker.
         if ($this->assignment->get_instance()->markingallocation &&
@@ -417,7 +414,6 @@ class assign_grading_table extends table_sql implements renderable {
 
         if ($assignment->get_instance()->teamsubmission) {
             $this->no_sorting('team');
-            $this->no_sorting('teamstatus');
         }
 
         $plugincolumnindex = 0;
@@ -557,7 +553,11 @@ class assign_grading_table extends table_sql implements renderable {
             return '';
         }
         if ($this->is_downloading()) {
-            return $markers[$row->allocatedmarker];
+            if (isset($markers[$row->allocatedmarker])) {
+                return fullname($markers[$row->allocatedmarker]);
+            } else {
+                return '';
+            }
         }
 
         if ($this->quickgrading && has_capability('mod/assign:manageallocations', $this->assignment->get_context()) &&
@@ -673,26 +673,6 @@ class assign_grading_table extends table_sql implements renderable {
         }
     }
 
-
-    /**
-     * Get the team status for this user.
-     *
-     * @param stdClass $row
-     * @return string The team name
-     */
-    public function col_teamstatus(stdClass $row) {
-        $submission = false;
-        $group = false;
-        $this->get_group_and_submission($row->id, $group, $submission, -1);
-
-        $status = '';
-        if ($submission) {
-            $status = $submission->status;
-        }
-        return get_string('submissionstatus_' . $status, 'assign');
-    }
-
-
     /**
      * Format a list of outcomes.
      *
@@ -906,7 +886,12 @@ class assign_grading_table extends table_sql implements renderable {
     public function col_timesubmitted(stdClass $row) {
         $o = '-';
 
-        if ($row->timesubmitted) {
+        $group = false;
+        $submission = false;
+        $this->get_group_and_submission($row->id, $group, $submission, -1);
+        if ($group && $submission && $submission->timemodified) {
+            $o = userdate($submission->timemodified);
+        } else if ($row->timesubmitted) {
             $o = userdate($row->timesubmitted);
         }
 
@@ -929,12 +914,23 @@ class assign_grading_table extends table_sql implements renderable {
             $due = $row->extensionduedate;
         }
 
+        $group = false;
+        $submission = false;
+        $this->get_group_and_submission($row->id, $group, $submission, -1);
+        if ($group && $submission) {
+            $timesubmitted = $submission->timemodified;
+            $status = $submission->status;
+        } else {
+            $timesubmitted = $row->timesubmitted;
+            $status = $row->status;
+        }
+
         if ($this->assignment->is_any_submission_plugin_enabled()) {
 
-            $o .= $this->output->container(get_string('submissionstatus_' . $row->status, 'assign'),
-                                           array('class'=>'submissionstatus' .$row->status));
-            if ($due && $row->timesubmitted > $due) {
-                $usertime = format_time($row->timesubmitted - $due);
+            $o .= $this->output->container(get_string('submissionstatus_' . $status, 'assign'),
+                                           array('class'=>'submissionstatus' .$status));
+            if ($due && $timesubmitted > $due) {
+                $usertime = format_time($timesubmitted - $due);
                 $latemessage = get_string('submittedlateshort',
                                           'assign',
                                           $usertime);
@@ -950,15 +946,14 @@ class assign_grading_table extends table_sql implements renderable {
                 $o .= $this->col_workflowstatus($row);
             } else if ($row->grade !== null && $row->grade >= 0) {
                 $o .= $this->output->container(get_string('graded', 'assign'), 'submissiongraded');
-            }
-
-            if (!$row->timesubmitted) {
+            } else if (!$timesubmitted) {
                 $now = time();
                 if ($due && ($now > $due)) {
                     $overduestr = get_string('overdue', 'assign', format_time($now - $due));
                     $o .= $this->output->container($overduestr, 'overduesubmission');
                 }
             }
+
             if ($row->extensionduedate) {
                 $userdate = userdate($row->extensionduedate);
                 $extensionstr = get_string('userextensiondate', 'assign', $userdate);
index 3c0e43b..a911fc8 100644 (file)
@@ -423,7 +423,6 @@ $string['teamsubmission'] = 'Students submit in groups';
 $string['teamsubmission_help'] = 'If enabled students will be divided into groups based on the default set of groups or a custom grouping. A group submission will be shared among group members and all members of the group will see each others changes to the submission.';
 $string['teamsubmissiongroupingid'] = 'Grouping for student groups';
 $string['teamsubmissiongroupingid_help'] = 'This is the grouping that the assignment will use to find groups for student groups. If not set - the default set of groups will be used.';
-$string['teamsubmissionstatus'] = 'Group submission status';
 $string['textinstructions'] = 'Assignment instructions';
 $string['timemodified'] = 'Last modified';
 $string['timeremaining'] = 'Time remaining';
index 562d264..f6037a4 100644 (file)
@@ -559,6 +559,7 @@ class mod_assign_renderer extends plugin_renderer_base {
         $row->cells = array($cell1, $cell2);
         $t->data[] = $row;
 
+        $submission = $status->teamsubmission ? $status->teamsubmission : $status->submission;
         $duedate = $status->duedate;
         if ($duedate > 0) {
             // Due date.
@@ -593,8 +594,8 @@ class mod_assign_renderer extends plugin_renderer_base {
             $row = new html_table_row();
             $cell1 = new html_table_cell(get_string('timeremaining', 'assign'));
             if ($duedate - $time <= 0) {
-                if (!$status->submission ||
-                        $status->submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
+                if (!$submission ||
+                        $submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
                     if ($status->submissionsenabled) {
                         $overduestr = get_string('overdue', 'assign', format_time($time - $duedate));
                         $cell2 = new html_table_cell($overduestr);
@@ -603,16 +604,16 @@ class mod_assign_renderer extends plugin_renderer_base {
                         $cell2 = new html_table_cell(get_string('duedatereached', 'assign'));
                     }
                 } else {
-                    if ($status->submission->timemodified > $duedate) {
+                    if ($submission->timemodified > $duedate) {
                         $latestr = get_string('submittedlate',
                                               'assign',
-                                              format_time($status->submission->timemodified - $duedate));
+                                              format_time($submission->timemodified - $duedate));
                         $cell2 = new html_table_cell($latestr);
                         $cell2->attributes = array('class'=>'latesubmission');
                     } else {
                         $earlystr = get_string('submittedearly',
                                                'assign',
-                                               format_time($status->submission->timemodified - $duedate));
+                                               format_time($submission->timemodified - $duedate));
                         $cell2 = new html_table_cell($earlystr);
                         $cell2->attributes = array('class'=>'earlysubmission');
                     }
@@ -649,7 +650,6 @@ class mod_assign_renderer extends plugin_renderer_base {
         }
 
         // Last modified.
-        $submission = $status->teamsubmission ? $status->teamsubmission : $status->submission;
         if ($submission) {
             $row = new html_table_row();
             $cell1 = new html_table_cell(get_string('timemodified', 'assign'));
index f43b0f6..d1cbbbc 100644 (file)
@@ -118,6 +118,173 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $this->editingteachers[0]->ignoresesskey = false;
     }
 
+    /**
+     * Test submissions with extension date.
+     */
+    public function test_gradingtable_extension_due_date() {
+        global $PAGE;
+
+        // Setup the assignment.
+        $this->create_extra_users();
+        $this->setUser($this->editingteachers[0]);
+        $assign = $this->create_instance(array(
+            'assignsubmission_onlinetext_enabled'=>1,
+            'duedate' => time() - 4 * 24 * 60 * 60,
+         ));
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
+            'id' => $assign->get_course_module()->id,
+            'action' => 'grading',
+        )));
+
+        // Check that the assignment is late.
+        $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
+        $output = $assign->get_renderer()->render($gradingtable);
+        $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
+        $this->assertContains(get_string('overdue', 'assign', format_time(4*24*60*60)), $output);
+
+        // Grant an extension.
+        $assign->testable_save_user_extension($this->students[0]->id, time() + 2 * 24 * 60 * 60);
+        $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
+        $output = $assign->get_renderer()->render($gradingtable);
+        $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
+        $this->assertContains(get_string('userextensiondate', 'assign', userdate(time() + 2*24*60*60)), $output);
+
+        // Simulate a submission.
+        $this->setUser($this->students[0]);
+        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
+        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
+        $data = new stdClass();
+        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
+                                         'text'=>'Submission text',
+                                         'format'=>FORMAT_MOODLE);
+        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
+        $plugin->save($submission, $data);
+
+        // Verify output.
+        $this->setUser($this->editingteachers[0]);
+        $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
+        $output = $assign->get_renderer()->render($gradingtable);
+        $this->assertContains(get_string('submissionstatus_submitted', 'assign'), $output);
+        $this->assertContains(get_string('userextensiondate', 'assign', userdate(time() + 2*24*60*60)), $output);
+    }
+
+    /**
+     * Test that late submissions with extension date calculate correctly.
+     */
+    public function test_gradingtable_extension_date_calculation_for_lateness() {
+        global $PAGE;
+
+        // Setup the assignment.
+        $this->create_extra_users();
+        $this->setUser($this->editingteachers[0]);
+        $assign = $this->create_instance(array(
+            'assignsubmission_onlinetext_enabled'=>1,
+            'duedate' => time() - 4 * 24 * 60 * 60,
+         ));
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
+            'id' => $assign->get_course_module()->id,
+            'action' => 'grading',
+        )));
+
+        // Check that the assignment is late.
+        $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
+        $output = $assign->get_renderer()->render($gradingtable);
+        $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
+        $this->assertContains(get_string('overdue', 'assign', format_time(4*24*60*60)), $output);
+
+        // Grant an extension that is in the past.
+        $assign->testable_save_user_extension($this->students[0]->id, time() - 2 * 24 * 60 * 60);
+        $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
+        $output = $assign->get_renderer()->render($gradingtable);
+        $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
+        $this->assertContains(get_string('userextensiondate', 'assign', userdate(time() - 2*24*60*60)), $output);
+        $this->assertContains(get_string('overdue', 'assign', format_time(2*24*60*60)), $output);
+
+        // Simulate a submission.
+        $this->setUser($this->students[0]);
+        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
+        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
+        $data = new stdClass();
+        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
+                                         'text'=>'Submission text',
+                                         'format'=>FORMAT_MOODLE);
+        $plugin = $assign->get_submission_plugin_by_type('onlinetext');
+        $plugin->save($submission, $data);
+
+        // Verify output.
+        $this->setUser($this->editingteachers[0]);
+        $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
+        $output = $assign->get_renderer()->render($gradingtable);
+        $this->assertContains(get_string('submissionstatus_submitted', 'assign'), $output);
+        $this->assertContains(get_string('userextensiondate', 'assign', userdate(time() - 2*24*60*60)), $output);
+        $this->assertContains(get_string('submittedlateshort', 'assign', format_time(2*24*60*60)), $output);
+    }
+
+    /**
+     * Check that group submission information is rendered correctly in the
+     * grading table.
+     */
+    public function test_gradingtable_group_submissions_rendering() {
+        global $PAGE;
+
+        $this->create_extra_users();
+        // Now verify group assignments.
+        $this->setUser($this->teachers[0]);
+        $assign = $this->create_instance(array(
+            'teamsubmission' => 1,
+            'assignsubmission_onlinetext_enabled' => 1,
+            'submissiondrafts' => 1,
+            'requireallteammemberssubmit' => 0,
+        ));
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
+            'id' => $assign->get_course_module()->id,
+            'action' => 'grading',
+        )));
+
+        // Add a submission.
+        $this->setUser($this->extrastudents[0]);
+        $data = new stdClass();
+        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
+                                         'text'=>'Submission text',
+                                         'format'=>FORMAT_MOODLE);
+        $notices = array();
+        $assign->save_submission($data, $notices);
+
+        $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
+        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
+        $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
+
+        // Check output.
+        $this->setUser($this->teachers[0]);
+        $gradingtable = new assign_grading_table($assign, 4, '', 0, true);
+        $output = $assign->get_renderer()->render($gradingtable);
+        $document = new DOMDocument();
+        $document->loadHTML($output);
+        $xpath = new DOMXPath($document);
+
+        // Check status.
+        $this->assertSame(get_string('submissionstatus_submitted', 'assign'), $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c4"]/div[@class="submissionstatussubmitted"])'));
+        $this->assertSame(get_string('submissionstatus_submitted', 'assign'), $xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c4"]/div[@class="submissionstatussubmitted"])'));
+
+        // Check submission last modified date
+        $this->assertGreaterThan(0, strtotime($xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c8"])')));
+        $this->assertGreaterThan(0, strtotime($xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c8"])')));
+
+        // Check group.
+        $this->assertSame($this->groups[0]->name, $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c5"])'));
+        $this->assertSame($this->groups[0]->name, $xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c5"])'));
+
+        // Check submission text.
+        $this->assertSame('Submission text', $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c9"]/div/div)'));
+        $this->assertSame('Submission text', $xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c9"]/div/div)'));
+
+        // Check comments can be made.
+        $this->assertSame(1, (int)$xpath->evaluate('count(//td[@id="mod_assign_grading_r0_c10"]//textarea)'));
+        $this->assertSame(1, (int)$xpath->evaluate('count(//td[@id="mod_assign_grading_r3_c10"]//textarea)'));
+    }
+
     public function test_show_intro() {
         // Test whether we are showing the intro at the correct times.
         $this->setUser($this->editingteachers[0]);
@@ -734,7 +901,7 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $this->assertEquals(null, $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->datesubmitted);
     }
 
-    public function test_group_submissions_submit_for_marking() {
+    public function test_group_submissions_submit_for_marking_requireallteammemberssubmit() {
         global $PAGE;
 
         $this->create_extra_users();
@@ -746,8 +913,8 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
                                                'requireallteammemberssubmit'=>1));
         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
 
-        $this->setUser($this->extrastudents[0]);
         // Add a submission.
+        $this->setUser($this->extrastudents[0]);
         $data = new stdClass();
         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
                                          'text'=>'Submission text',
@@ -780,6 +947,59 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
     }
 
+    public function test_group_submissions_submit_for_marking() {
+        global $PAGE;
+
+        $this->create_extra_users();
+        // Now verify group assignments.
+        $this->setUser($this->editingteachers[0]);
+        $assign = $this->create_instance(array('teamsubmission'=>1,
+                                               'assignsubmission_onlinetext_enabled'=>1,
+                                               'submissiondrafts'=>1,
+                                               'requireallteammemberssubmit'=>0,
+                                               'duedate' => time() - 2*24*60*60));
+        $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
+
+        $this->setUser($this->extrastudents[0]);
+        // Add a submission.
+        $data = new stdClass();
+        $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
+                                         'text'=>'Submission text',
+                                         'format'=>FORMAT_MOODLE);
+
+        $notices = array();
+        $assign->save_submission($data, $notices);
+
+        // Check we can see the submit button.
+        $output = $assign->view_student_summary($this->extrastudents[0], true);
+        $this->assertContains(get_string('submitassignment', 'assign'), $output);
+        $this->assertContains(get_string('timeremaining', 'assign'), $output);
+        $this->assertContains(get_string('overdue', 'assign', format_time(2*24*60*60)), $output);
+
+        $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
+        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
+        $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
+
+        // Check that the student does not see "Submit" button.
+        $output = $assign->view_student_summary($this->extrastudents[0], true);
+        $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
+
+        // Change to another user in the same group.
+        $this->setUser($this->extrastudents[self::GROUP_COUNT]);
+        $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
+        $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
+
+        // Check that time remaining is not overdue.
+        $this->assertContains(get_string('timeremaining', 'assign'), $output);
+        $this->assertContains(get_string('submittedlate', 'assign', format_time(2*24*60*60)), $output);
+
+        $submission = $assign->get_group_submission($this->extrastudents[self::GROUP_COUNT]->id, 0, true);
+        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
+        $assign->testable_update_submission($submission, $this->extrastudents[self::GROUP_COUNT]->id, true, true);
+        $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
+        $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
+    }
+
     public function test_submissions_open() {
         $this->setUser($this->editingteachers[0]);
 
index 304e5d7..e086e12 100644 (file)
@@ -177,12 +177,12 @@ class feedback_item_textarea extends feedback_item_base {
         $data = $analysed_item->data;
         if (is_array($data)) {
             if (isset($data[0])) {
-                $worksheet->write_string($row_offset, 2, $data[0], $xls_formats->value_bold);
+                $worksheet->write_string($row_offset, 2, htmlspecialchars_decode($data[0], ENT_QUOTES), $xls_formats->value_bold);
             }
             $row_offset++;
             $sizeofdata = count($data);
             for ($i = 1; $i < $sizeofdata; $i++) {
-                $worksheet->write_string($row_offset, 2, $data[$i], $xls_formats->default);
+                $worksheet->write_string($row_offset, 2, htmlspecialchars_decode($data[$i], ENT_QUOTES), $xls_formats->default);
                 $row_offset++;
             }
         }
index ccbf806..77027c1 100644 (file)
@@ -167,11 +167,11 @@ class feedback_item_textfield extends feedback_item_base {
         $worksheet->write_string($row_offset, 1, $item->name, $xls_formats->head2);
         $data = $analysed_item->data;
         if (is_array($data)) {
-            $worksheet->write_string($row_offset, 2, $data[0], $xls_formats->value_bold);
+            $worksheet->write_string($row_offset, 2, htmlspecialchars_decode($data[0], ENT_QUOTES), $xls_formats->value_bold);
             $row_offset++;
             $sizeofdata = count($data);
             for ($i = 1; $i < $sizeofdata; $i++) {
-                $worksheet->write_string($row_offset, 2, $data[$i], $xls_formats->default);
+                $worksheet->write_string($row_offset, 2, htmlspecialchars_decode($data[$i], ENT_QUOTES), $xls_formats->default);
                 $row_offset++;
             }
         }
index 96eeb59..711ea10 100644 (file)
@@ -49,7 +49,7 @@ class user_report_viewed extends \core\event\base {
      */
     protected function init() {
         $this->data['crud'] = 'r';
-        $this->data['edulevel'] = self::LEVEL_OTHER;
+        $this->data['edulevel'] = self::LEVEL_PARTICIPATING;
     }
 
     /**
index 45cda24..024db75 100644 (file)
@@ -1358,10 +1358,68 @@ function forum_user_complete($course, $user, $mod, $forum) {
     }
 }
 
+/**
+ * Filters the forum discussions according to groups membership and config.
+ *
+ * @since  Moodle 2.8, 2.7.1, 2.6.4
+ * @param  array $discussions Discussions with new posts array
+ * @return array Forums with the number of new posts
+ */
+function forum_filter_user_groups_discussions($discussions) {
+
+    // Group the remaining discussions posts by their forumid.
+    $filteredforums = array();
+
+    // Discard not visible groups.
+    foreach ($discussions as $discussion) {
+
+        // Course data is already cached.
+        $instances = get_fast_modinfo($discussion->course)->get_instances();
+        $forum = $instances['forum'][$discussion->forum];
+
+        // Continue if the user should not see this discussion.
+        if (!forum_is_user_group_discussion($forum, $discussion->groupid)) {
+            continue;
+        }
+
+        // Grouping results by forum.
+        if (empty($filteredforums[$forum->instance])) {
+            $filteredforums[$forum->instance] = new stdClass();
+            $filteredforums[$forum->instance]->id = $forum->id;
+            $filteredforums[$forum->instance]->count = 0;
+        }
+        $filteredforums[$forum->instance]->count += $discussion->count;
 
+    }
+
+    return $filteredforums;
+}
+
+/**
+ * Returns whether the discussion group is visible by the current user or not.
+ *
+ * @since Moodle 2.8, 2.7.1, 2.6.4
+ * @param cm_info $cm The discussion course module
+ * @param int $discussiongroupid The discussion groupid
+ * @return bool
+ */
+function forum_is_user_group_discussion(cm_info $cm, $discussiongroupid) {
+
+    if ($discussiongroupid == -1 || $cm->effectivegroupmode != SEPARATEGROUPS) {
+        return true;
+    }
 
+    if (isguestuser()) {
+        return false;
+    }
 
+    if (has_capability('moodle/site:accessallgroups', context_module::instance($cm->id)) ||
+            in_array($discussiongroupid, $cm->get_modinfo()->get_groups($cm->groupingid))) {
+        return true;
+    }
 
+    return false;
+}
 
 /**
  * @global object
@@ -1388,12 +1446,12 @@ function forum_print_overview($courses,&$htmlarray) {
 
         // If the user has never entered into the course all posts are pending
         if ($course->lastaccess == 0) {
-            $coursessqls[] = '(f.course = ?)';
+            $coursessqls[] = '(d.course = ?)';
             $params[] = $course->id;
 
         // Only posts created after the course last access
         } else {
-            $coursessqls[] = '(f.course = ? AND p.created > ?)';
+            $coursessqls[] = '(d.course = ? AND p.created > ?)';
             $params[] = $course->id;
             $params[] = $course->lastaccess;
         }
@@ -1401,18 +1459,20 @@ function forum_print_overview($courses,&$htmlarray) {
     $params[] = $USER->id;
     $coursessql = implode(' OR ', $coursessqls);
 
-    $sql = "SELECT f.id, COUNT(*) as count "
-                .'FROM {forum} f '
-                .'JOIN {forum_discussions} d ON d.forum  = f.id '
+    $sql = "SELECT d.id, d.forum, d.course, d.groupid, COUNT(*) as count "
+                .'FROM {forum_discussions} d '
                 .'JOIN {forum_posts} p ON p.discussion = d.id '
                 ."WHERE ($coursessql) "
                 .'AND p.userid != ? '
-                .'GROUP BY f.id';
+                .'GROUP BY d.id, d.forum, d.course, d.groupid';
 
-    if (!$new = $DB->get_records_sql($sql, $params)) {
-        $new = array(); // avoid warnings
+    // Avoid warnings.
+    if (!$discussions = $DB->get_records_sql($sql, $params)) {
+        $discussions = array();
     }
 
+    $forumsnewposts = forum_filter_user_groups_discussions($discussions);
+
     // also get all forum tracking stuff ONCE.
     $trackingforums = array();
     foreach ($forums as $forum) {
@@ -1459,7 +1519,7 @@ function forum_print_overview($courses,&$htmlarray) {
         $unread = array();
     }
 
-    if (empty($unread) and empty($new)) {
+    if (empty($unread) and empty($forumsnewposts)) {
         return;
     }
 
@@ -1471,8 +1531,8 @@ function forum_print_overview($courses,&$htmlarray) {
         $thisunread = 0;
         $showunread = false;
         // either we have something from logs, or trackposts, or nothing.
-        if (array_key_exists($forum->id, $new) && !empty($new[$forum->id])) {
-            $count = $new[$forum->id]->count;
+        if (array_key_exists($forum->id, $forumsnewposts) && !empty($forumsnewposts[$forum->id])) {
+            $count = $forumsnewposts[$forum->id]->count;
         }
         if (array_key_exists($forum->id,$unread)) {
             $thisunread = $unread[$forum->id]->count;
@@ -1561,25 +1621,11 @@ function forum_print_recent_activity($course, $viewfullnames, $timestart) {
             }
         }
 
-        $groupmode = groups_get_activity_groupmode($cm, $course);
-
-        if ($groupmode) {
-            if ($post->groupid == -1 or $groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
-                // oki (Open discussions have groupid -1)
-            } else {
-                // separate mode
-                if (isguestuser()) {
-                    // shortcut
-                    continue;
-                }
-
-                if (!in_array($post->groupid, $modinfo->get_groups($cm->groupingid))) {
-                    continue;
-                }
-            }
+        // Check that the user can see the discussion.
+        if (forum_is_user_group_discussion($cm, $post->groupid)) {
+            $printposts[] = $post;
         }
 
-        $printposts[] = $post;
     }
     unset($posts);
 
index 6cd03e6..aaa9e01 100644 (file)
@@ -49,7 +49,7 @@ class backup_quiz_activity_structure_step extends backup_questions_activity_stru
             'questionsperpage', 'navmethod', 'shufflequestions', 'shuffleanswers',
             'sumgrades', 'grade', 'timecreated',
             'timemodified', 'password', 'subnet', 'browsersecurity',
-            'delay1', 'delay2', 'showuserpicture', 'showblocks'));
+            'delay1', 'delay2', 'showuserpicture', 'showblocks', 'completionattemptsexhausted', 'completionpass'));
 
         // Define elements for access rule subplugin settings.
         $this->add_subplugin_structure('quizaccess', $quiz, true);
index 14f2fde..85fe13d 100644 (file)
@@ -44,6 +44,8 @@
         <FIELD NAME="delay2" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Delay that must be left between the second and subsequent attempt, in seconds."/>
         <FIELD NAME="showuserpicture" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Option to show the user's picture during the attempt and on the review page."/>
         <FIELD NAME="showblocks" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether blocks should be shown on the attempt.php and review.php pages."/>
+        <FIELD NAME="completionattemptsexhausted" TYPE="int" LENGTH="1" NOTNULL="false" DEFAULT="0" SEQUENCE="false"/>
+        <FIELD NAME="completionpass" TYPE="int" LENGTH="1" NOTNULL="false" DEFAULT="0" SEQUENCE="false"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
index 0a8ba8d..2110673 100644 (file)
@@ -776,6 +776,33 @@ function xmldb_quiz_upgrade($oldversion) {
     // Moodle v2.7.0 release upgrade line.
     // Put any upgrade step following this.
 
+    if ($oldversion < 2014052800) {
+
+        // Define field completionattemptsexhausted to be added to quiz.
+        $table = new xmldb_table('quiz');
+        $field = new xmldb_field('completionattemptsexhausted', XMLDB_TYPE_INTEGER, '1', null, null, null, '0', 'showblocks');
+
+        // Conditionally launch add field completionattemptsexhausted.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+        // Quiz savepoint reached.
+        upgrade_mod_savepoint(true, 2014052800, 'quiz');
+    }
+
+    if ($oldversion < 2014052801) {
+        // Define field completionpass to be added to quiz.
+        $table = new xmldb_table('quiz');
+        $field = new xmldb_field('completionpass', XMLDB_TYPE_INTEGER, '1', null, null, null, 0, 'completionattemptsexhausted');
+
+        // Conditionally launch add field completionpass.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+        // Quiz savepoint reached.
+        upgrade_mod_savepoint(true, 2014052801, 'quiz');
+    }
     return true;
 }
 
index 2ebae5f..22d4784 100644 (file)
@@ -152,6 +152,10 @@ $string['comment'] = 'Comment';
 $string['commentorgrade'] = 'Make comment or override grade';
 $string['comments'] = 'Comments';
 $string['completedon'] = 'Completed on';
+$string['completionpass'] = 'Require passing grade';
+$string['completionpass_help'] = 'If enabled, this activity is considered complete when the student receives a passing grade, with the pass grade set in the gradebook.';
+$string['completionattemptsexhausted'] = 'Or all available attempts completed';
+$string['completionattemptsexhausted_help'] = 'Mark quiz complete when the student has exhausted the maximum number of attempts.';
 $string['configadaptive'] = 'If you choose Yes for this option then the student will be allowed multiple responses to a question even within the same attempt at the quiz.';
 $string['configattemptsallowed'] = 'Restriction on the number of attempts students are allowed at the quiz.';
 $string['configdecimaldigits'] = 'Number of digits that should be shown after the decimal point when displaying grades.';
index fdfb418..d4cba45 100644 (file)
@@ -1560,6 +1560,7 @@ function quiz_supports($feature) {
         case FEATURE_GROUPMEMBERSONLY:          return true;
         case FEATURE_MOD_INTRO:                 return true;
         case FEATURE_COMPLETION_TRACKS_VIEWS:   return true;
+        case FEATURE_COMPLETION_HAS_RULES:      return true;
         case FEATURE_GRADE_HAS_GRADE:           return true;
         case FEATURE_GRADE_OUTCOMES:            return true;
         case FEATURE_BACKUP_MOODLE2:            return true;
@@ -1790,3 +1791,54 @@ function quiz_get_navigation_options() {
         QUIZ_NAVMETHOD_SEQ  => get_string('navmethod_seq', 'quiz')
     );
 }
+
+
+/**
+ * Obtains the automatic completion state for this quiz on any conditions
+ * in quiz settings, such as if all attempts are used or a certain grade is achieved.
+ *
+ * @param object $course Course
+ * @param object $cm Course-module
+ * @param int $userid User ID
+ * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
+ * @return bool True if completed, false if not. (If no conditions, then return
+ *   value depends on comparison type)
+ */
+function quiz_get_completion_state($course, $cm, $userid, $type) {
+    global $DB;
+    global $CFG;
+
+    $quiz = $DB->get_record('quiz', array('id' => $cm->instance), '*', MUST_EXIST);
+    if (!$quiz->completionattemptsexhausted && !$quiz->completionpass) {
+        return $type;
+    }
+
+    // Check if the user has used up all attempts.
+    if ($quiz->completionattemptsexhausted) {
+        $attempts = quiz_get_user_attempts($quiz->id, $userid, 'finished', true);
+        if ($attempts) {
+            $lastfinishedattempt = end($attempts);
+            $context = context_module::instance($cm->id);
+            $quizobj = quiz::create($quiz->id, $userid);
+            $accessmanager = new quiz_access_manager($quizobj, time(),
+                    has_capability('mod/quiz:ignoretimelimits', $context, $userid, false));
+            if ($accessmanager->is_finished(count($attempts), $lastfinishedattempt)) {
+                return true;
+            }
+        }
+    }
+
+    // Check for passing grade.
+    if ($quiz->completionpass) {
+        require_once($CFG->libdir . '/gradelib.php');
+        $item = grade_item::fetch(array('courseid' => $course->id, 'itemtype' => 'mod',
+                'itemmodule' => 'quiz', 'iteminstance' => $cm->instance));
+        if ($item) {
+            $grades = grade_grade::fetch_users_grades($item, array($userid), false);
+            if (!empty($grades[$userid])) {
+                return $grades[$userid]->is_passed($item);
+            }
+        }
+    }
+    return false;
+}
index ffa7f86..ce078fa 100644 (file)
@@ -1641,6 +1641,11 @@ function quiz_attempt_submitted_handler($event) {
         return true;
     }
 
+    // Update completion state.
+    $completion = new completion_info($course);
+    if ($completion->is_enabled($cm) && ($quiz->completionattemptsexhausted || $quiz->completionpass)) {
+        $completion->update_state($cm, COMPLETION_COMPLETE, $event->userid);
+    }
     return quiz_send_notification_messages($course, $quiz, $attempt,
             context_module::instance($cm->id), $cm);
 }
index efd0e8a..912bcae 100644 (file)
@@ -585,4 +585,37 @@ class mod_quiz_mod_form extends moodleform_mod {
 
         return $errors;
     }
+
+    /**
+     * Display module-specific activity completion rules.
+     * Part of the API defined by moodleform_mod
+     * @return array Array of string IDs of added items, empty array if none
+     */
+    public function add_completion_rules() {
+        $mform = $this->_form;
+        $items = array();
+
+        $group = array();
+        $group[] = $mform->createElement('advcheckbox', 'completionpass', null, get_string('completionpass', 'quiz'),
+                array('group' => 'cpass'));
+
+        $group[] = $mform->createElement('advcheckbox', 'completionattemptsexhausted', null,
+                get_string('completionattemptsexhausted', 'quiz'),
+                array('group' => 'cattempts'));
+        $mform->disabledIf('completionattemptsexhausted', 'completionpass', 'notchecked');
+        $mform->addGroup($group, 'completionpassgroup', get_string('completionpass', 'quiz'), ' &nbsp; ', false);
+        $mform->addHelpButton('completionpassgroup', 'completionpass', 'quiz');
+        $items[] = 'completionpassgroup';
+        return $items;
+    }
+
+    /**
+     * Called during validation. Indicates whether a module-specific completion rule is selected.
+     *
+     * @param array $data Input data (not yet validated)
+     * @return bool True if one or more rules is enabled, false if none are.
+     */
+    public function completion_rule_enabled($data) {
+        return !empty($data['completionattemptsexhausted']) || !empty($data['completionpass']);
+    }
 }
diff --git a/mod/quiz/tests/behat/completion_condition_attempts_used.feature b/mod/quiz/tests/behat/completion_condition_attempts_used.feature
new file mode 100644 (file)
index 0000000..d1684dd
--- /dev/null
@@ -0,0 +1,88 @@
+@mod @mod_quiz
+Feature: Set a quiz to be marked complete when the student uses all attempts allowed
+  In order to ensure a student has learned the material before being marked complete
+  As a teacher
+  I need to set a quiz to complete when the student receives a passing grade, or completed_fail if they use all attempts without passing
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | student1 | Student | 1 | student1@asd.com |
+      | teacher1 | Teacher | 1 | teacher1@asd.com |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And I log in as "admin"
+    And I set the following administration settings values:
+     | Enable completion tracking | 1 |
+    And I expand "Grades" node
+    And I follow "Grade item settings"
+    And I set the field "Advanced grade item options" to "hiddenuntil"
+    And I press "Save changes"
+    And I log out
+
+  Scenario: student1 uses up both attempts without passing
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I click on "Edit settings" "link" in the "Administration" "block"
+    And I set the following fields to these values:
+      | Enable completion tracking | Yes |
+    And I press "Save changes"
+    And I add a "Quiz" to section "1" and I fill the form with:
+      | Name        | Test quiz name        |
+      | Description | Test quiz description |
+      | Completion tracking | Show activity as complete when conditions are met |
+      | Attempts allowed | 2 |
+      | Require passing grade | 1 |
+      | Or all available attempts completed | 1 |
+    And I add a "True/False" question to the "Test quiz name" quiz with:
+      | Question name                      | First question                          |
+      | Question text                      | Answer the first question               |
+      | General feedback                   | Thank you, this is the general feedback |
+      | Correct answer                     | True                                    |
+      | Feedback for the response 'True'.  | So you think it is true                 |
+      | Feedback for the response 'False'. | So you think it is false                |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I follow "Simple view"
+    And I follow "Edit  quiz Test quiz name"
+    Then I should see "Edit grade item"
+    And I set the field "gradepass" to "5"
+    And I press "Save changes"
+    And I should see "Simple view"
+    Then I log out
+
+    And I log in as "student1"
+    And I follow "Course 1"
+    And "//img[contains(@alt, 'Not completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
+    And I follow "Test quiz name"
+    And I press "Attempt quiz now"
+    And I should see "Question 1"
+    And I should see "Answer the first question"
+    And I set the field "False" to "1"
+    And I press "Next"
+    And I should see "Answer saved"
+    And I press "Submit all and finish"
+    And I follow "C1"
+    And "//img[contains(@alt, 'Not completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
+    And I follow "Test quiz name"
+    And I press "Re-attempt quiz"
+    Then I should see "Question 1"
+    And I should see "Answer the first question"
+    And I set the field "False" to "1"
+    And I press "Next"
+    And I should see "Answer saved"
+    And I press "Submit all and finish"
+    And I follow "C1"
+    And "//img[contains(@alt, 'Completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
+    And I log out
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Activity completion"
+    Then "//img[contains(@title,'Test quiz name') and @alt='Completed']" "xpath_element" should exist in the "Student 1" "table_row"
+
diff --git a/mod/quiz/tests/behat/completion_condition_passing_grade.feature b/mod/quiz/tests/behat/completion_condition_passing_grade.feature
new file mode 100644 (file)
index 0000000..90c18c6
--- /dev/null
@@ -0,0 +1,87 @@
+@mod @mod_quiz
+Feature: Set a quiz to be marked complete when the student passes
+  In order to ensure a student has learned the material before being marked complete
+  As a teacher
+  I need to set a quiz to complete when the student recieves a passing grade
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | student1 | Student | 1 | student1@asd.com |
+      | teacher1 | Teacher | 1 | teacher1@asd.com |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And I log in as "admin"
+    And I set the following administration settings values:
+     | Enable completion tracking | 1 |
+    And I expand "Grades" node
+    And I follow "Grade item settings"
+    And I set the field "Advanced grade item options" to "hiddenuntil"
+    And I press "Save changes"
+    And I log out
+
+  Scenario: student1 passes on the first try
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I click on "Edit settings" "link" in the "Administration" "block"
+    And I set the following fields to these values:
+      | Enable completion tracking | Yes |
+    And I press "Save changes"
+    And I add a "Quiz" to section "1" and I fill the form with:
+      | Name        | Test quiz name        |
+      | Description | Test quiz description |
+      | Completion tracking | Show activity as complete when conditions are met |
+      | Attempts allowed | 4 |
+      | Require passing grade | 1 |
+    And I add a "True/False" question to the "Test quiz name" quiz with:
+      | Question name                      | First question                          |
+      | Question text                      | Answer the first question               |
+      | General feedback                   | Thank you, this is the general feedback |
+      | Correct answer                     | True                                    |
+      | Feedback for the response 'True'.  | So you think it is true                 |
+      | Feedback for the response 'False'. | So you think it is false                |
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I set the field "jump" to "Simple view"
+    And I press "Go"
+    And I follow "Edit  quiz Test quiz name"
+    Then I should see "Edit grade item"
+    And I set the field "gradepass" to "5"
+    And I press "Save changes"
+    Then I should see "Simple view"
+    And I log out
+
+    And I log in as "student1"
+    And I follow "Course 1"
+    And "//img[contains(@alt, 'Not completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
+    And I follow "Test quiz name"
+    And I press "Attempt quiz now"
+    Then I should see "Question 1"
+    And I should see "Answer the first question"
+    And I set the field "False" to "1"
+    And I press "Next"
+    And I should see "Answer saved"
+    And I press "Submit all and finish"
+    And I follow "C1"
+    And "//img[contains(@alt, 'Not completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
+    And I follow "Test quiz name"
+    And I press "Re-attempt quiz"
+    Then I should see "Question 1"
+    And I should see "Answer the first question"
+    And I set the field "True" to "1"
+    And I press "Next"
+    And I should see "Answer saved"
+    And I press "Submit all and finish"
+    And I follow "C1"
+    And "//img[contains(@alt, 'Completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
+    And I log out
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Activity completion"
+    Then "//img[contains(@title,'Test quiz name') and @alt='Completed']" "xpath_element" should exist in the "Student 1" "table_row"
index 06828f8..0d368c8 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200; // The current module version (Date: YYYYMMDDXX).
+$plugin->version   = 2014052801; // The current module version (Date: YYYYMMDDXX).
 $plugin->requires  = 2014050800; // Requires this Moodle version.
 $plugin->component = 'mod_quiz'; // Full name of the plugin (used for diagnostics).
 $plugin->cron      = 60;
similarity index 81%
rename from mod/scorm/datamodels/aicc.js.php
rename to mod/scorm/datamodels/aicc.js
index cbf64b4..90240f3 100644 (file)
@@ -1,4 +1,3 @@
-<?php
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-if (isset($userdata->status)) {
-    if ($userdata->status == '') {
-        $userdata->entry = 'ab-initio';
-    } else {
-        if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {
-            $userdata->entry = 'resume';
-        } else {
-            $userdata->entry = '';
-        }
-    }
-}
-if (!isset($currentorg)) {
-    $currentorg = '';
-}
-?>
 //
 // SCORM 1.2 API Implementation
 //
-function AICCapi() {
+function AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, viewmode, currentorg, sesskey, cmid) {
+
+    var prerequrl = cfgwwwroot + "/mod/scorm/prereqs.php?a="+scormid+"&scoid="+scoid+"&attempt="+attempt+"&mode="+viewmode+"&currentorg="+currentorg+"&sesskey="+sesskey;
+    var datamodelurl = cfgwwwroot + "/mod/scorm/datamodel.php";
+    var datamodelurlparams = "id="+cmid+"&a="+scormid+"&sesskey="+sesskey+"&attempt="+attempt+"&scoid="+scoid;
+
     // Standard Data Type Definition
     CMIString256 = '^.{0,255}$';
     CMIString4096 = '^.{0,4096}$';
@@ -75,23 +64,23 @@ function AICCapi() {
         'cmi._children':{'defaultvalue':cmi_children, 'mod':'r', 'writeerror':'402'},
         'cmi._version':{'defaultvalue':'3.4', 'mod':'r', 'writeerror':'402'},
         'cmi.core._children':{'defaultvalue':core_children, 'mod':'r', 'writeerror':'402'},
-        'cmi.core.student_id':{'defaultvalue':'<?php echo $userdata->student_id ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.core.student_name':{'defaultvalue':'<?php echo $userdata->student_name ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.core.lesson_location':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.lesson_location'})?$userdata->{'cmi.core.lesson_location'}:'' ?>', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
-        'cmi.core.credit':{'defaultvalue':'<?php echo $userdata->credit ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.core.lesson_status':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.lesson_status'})?$userdata->{'cmi.core.lesson_status'}:'' ?>', 'format':CMIStatus, 'mod':'rw', 'writeerror':'405'},
-        'cmi.core.exit':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.exit'})?$userdata->{'cmi.core.exit'}:'' ?>', 'format':CMIExit, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
-        'cmi.core.entry':{'defaultvalue':'<?php echo $userdata->entry ?>', 'mod':'r', 'writeerror':'403'},
+        'cmi.core.student_id':{'defaultvalue':def['cmi.core.student_id'], 'mod':'r', 'writeerror':'403'},
+        'cmi.core.student_name':{'defaultvalue':def['cmi.core.student_name'], 'mod':'r', 'writeerror':'403'},
+        'cmi.core.lesson_location':{'defaultvalue':def['cmi.core.lesson_location'], 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
+        'cmi.core.credit':{'defaultvalue':def['cmi.core.credit'], 'mod':'r', 'writeerror':'403'},
+        'cmi.core.lesson_status':{'defaultvalue':def['cmi.core.lesson_status'], 'format':CMIStatus, 'mod':'rw', 'writeerror':'405'},
+        'cmi.core.exit':{'defaultvalue':def['cmi.core.exit'], 'format':CMIExit, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
+        'cmi.core.entry':{'defaultvalue':def['cmi.core.entry'], 'mod':'r', 'writeerror':'403'},
         'cmi.core.score._children':{'defaultvalue':score_children, 'mod':'r', 'writeerror':'402'},
-        'cmi.core.score.raw':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.raw'})?$userdata->{'cmi.core.score.raw'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
-        'cmi.core.score.max':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.max'})?$userdata->{'cmi.core.score.max'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
-        'cmi.core.score.min':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.min'})?$userdata->{'cmi.core.score.min'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
+        'cmi.core.score.raw':{'defaultvalue':def['cmi.core.score.raw'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
+        'cmi.core.score.max':{'defaultvalue':def['cmi.core.score.max'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
+        'cmi.core.score.min':{'defaultvalue':def['cmi.core.score.min'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
         'cmi.core.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'00:00:00', 'readerror':'404', 'writeerror':'405'},
-        'cmi.core.total_time':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.total_time'})?$userdata->{'cmi.core.total_time'}:'00:00:00' ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.core.lesson_mode':{'defaultvalue':'<?php echo $userdata->mode ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.suspend_data':{'defaultvalue':'<?php echo isset($userdata->{'cmi.suspend_data'})?$userdata->{'cmi.suspend_data'}:'' ?>', 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
-        'cmi.launch_data':{'defaultvalue':'<?php echo isset($userdata->datafromlms)?$userdata->datafromlms:'' ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.comments':{'defaultvalue':'<?php echo isset($userdata->{'cmi.comments'})?$userdata->{'cmi.comments'}:'' ?>', 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
+        'cmi.core.total_time':{'defaultvalue':def['cmi.core.total_time'], 'mod':'r', 'writeerror':'403'},
+        'cmi.core.lesson_mode':{'defaultvalue':def['cmi.core.lesson_mode'], 'mod':'r', 'writeerror':'403'},
+        'cmi.suspend_data':{'defaultvalue':def['cmi.suspend_data'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
+        'cmi.launch_data':{'defaultvalue':def['cmi.launch_data'], 'mod':'r', 'writeerror':'403'},
+        'cmi.comments':{'defaultvalue':def['cmi.comments'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
         // deprecated evaluation attributes
         'cmi.evaluation.comments._count':{'defaultvalue':'0', 'mod':'r', 'writeerror':'402'},
         'cmi.evaluation.comments._children':{'defaultvalue':comments_children, 'mod':'r', 'writeerror':'402'},
@@ -108,16 +97,16 @@ function AICCapi() {
         'cmi.objectives.n.score.max':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
         'cmi.objectives.n.status':{'pattern':CMIIndex, 'format':CMIStatus2, 'mod':'rw', 'writeerror':'405'},
         'cmi.student_data._children':{'defaultvalue':student_data_children, 'mod':'r', 'writeerror':'402'},
-        'cmi.student_data.attempt_number':{'defaultvalue':'<?php echo isset($userdata->{'cmi.student_data.attempt_number'})?$userdata->{'cmi.student_data.attempt_number'}:'' ?>', 'mod':'r', 'writeerror':'402'},
+        'cmi.student_data.attempt_number':{'defaultvalue':def['cmi.student_data.attempt_number'], 'mod':'r', 'writeerror':'402'},
         'cmi.student_data.tries.n.score.raw':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
         'cmi.student_data.tries.n.score.min':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
         'cmi.student_data.tries.n.score.max':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
         'cmi.student_data.tries.n.status':{'pattern':CMIIndex, 'format':CMIStatus2, 'mod':'rw', 'writeerror':'405'},
         'cmi.student_data.tries.n.time':{'pattern':CMIIndex, 'format':CMITime, 'mod':'rw', 'writeerror':'405'},
-        'cmi.student_data.mastery_score':{'defaultvalue':'<?php echo isset($userdata->mastery_score)?$userdata->mastery_score:'' ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.student_data.max_time_allowed':{'defaultvalue':'<?php echo isset($userdata->max_time_allowed)?$userdata->max_time_allowed:'' ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.student_data.time_limit_action':{'defaultvalue':'<?php echo isset($userdata->time_limit_action)?$userdata->time_limit_action:'' ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.student_data.tries_during_lesson':{'defaultvalue':'<?php echo isset($userdata->{'cmi.student_data.tries_during_lesson'})?$userdata->{'cmi.student_data.tries_during_lesson'}:'' ?>', 'mod':'r', 'writeerror':'402'},
+        'cmi.student_data.mastery_score':{'defaultvalue':def['cmi.student_data.mastery_score'], 'mod':'r', 'writeerror':'403'},
+        'cmi.student_data.max_time_allowed':{'defaultvalue':def['cmi.student_data.max_time_allowed'], 'mod':'r', 'writeerror':'403'},
+        'cmi.student_data.time_limit_action':{'defaultvalue':def['cmi.student_data.time_limit_action'], 'mod':'r', 'writeerror':'403'},
+        'cmi.student_data.tries_during_lesson':{'defaultvalue':def['cmi.student_data.tries_during_lesson'], 'mod':'r', 'writeerror':'402'},
         'cmi.student_preference._children':{'defaultvalue':student_preference_children, 'mod':'r', 'writeerror':'402'},
         'cmi.student_preference.audio':{'defaultvalue':'0', 'format':CMISInteger, 'range':audio_range, 'mod':'rw', 'writeerror':'405'},
         'cmi.student_preference.language':{'defaultvalue':'', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
@@ -166,33 +155,7 @@ function AICCapi() {
         }
     }
 
-<?php
-$current_objective = '';
-$count = 0;
-$objectives = '';
-foreach ($userdata as $element => $value) {
-    if (substr($element, 0, 14) == 'cmi.objectives') {
-        $element = preg_replace('/\.(\d+)\./', "_\$1.", $element);
-        preg_match('/\_(\d+)\./', $element, $matches);
-        if (count($matches) > 0 && $current_objective != $matches[1]) {
-            $current_objective = $matches[1];
-            $count++;
-            $end = strpos($element, $matches[1])+strlen($matches[1]);
-            $subelement = substr($element, 0, $end);
-            echo '    '.$subelement." = new Object();\n";
-            echo '    '.$subelement.".score = new Object();\n";
-            echo '    '.$subelement.".score._children = score_children;\n";
-            echo '    '.$subelement.".score.raw = '';\n";
-            echo '    '.$subelement.".score.min = '';\n";
-            echo '    '.$subelement.".score.max = '';\n";
-        }
-        echo '    '.$element.' = \''.$value."';\n";
-    }
-}
-if ($count > 0) {
-    echo '    cmi.objectives._count = '.$count.";\n";
-}
-?>
+    eval(cmiobj);
 
     if (cmi.core.lesson_status == '') {
         cmi.core.lesson_status = 'not attempted';
@@ -232,16 +195,15 @@ if ($count > 0) {
                         setTimeout('mod_scorm_launch_prev_sco();',500);
                     }
                 } else {
-                    if (<?php echo $scorm->auto ?> == 1) {
+                    if (scormauto == 1) {
                         setTimeout('mod_scorm_launch_next_sco();',500);
                     }
                 }
                 // trigger TOC update
-                var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
                 var callback = M.mod_scorm.connectPrereqCallback;
                 YUI().use('io-base', function(Y) {
                     Y.on('io:complete', callback.success, Y);
-                    Y.io(sURL);
+                    Y.io(prerequrl);
                 });
                 return "true";
             } else {
@@ -549,12 +511,10 @@ if ($count > 0) {
         } else {
             datastring = CollectData(data,'cmi');
         }
-        datastring += '&attempt=<?php echo $attempt ?>';
-        datastring += '&scoid=<?php echo $scoid ?>';
 
         //popupwin(datastring);
         var myRequest = NewHttpReq();
-        result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/datamodel.php","id=<?php p($id) ?>&sesskey=<?php echo sesskey() ?>"+datastring);
+        result = DoRequest(myRequest,datamodelurl,datamodelurlparams+datastring);
         results = String(result).split('\n');
         errorCode = results[1];
         return results[0];
@@ -570,4 +530,8 @@ if ($count > 0) {
     this.LMSGetDiagnostic = LMSGetDiagnostic;
 }
 
-var API = new AICCapi();
+M.scorm_api = {};
+
+M.scorm_api.init = function(Y, def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, viewmode, currentorg, sesskey, cmid) {
+    window.API = new AICCapi(def, cmiobj, scormauto, cfgwwwroot, scormid, scoid, attempt, viewmode, currentorg, sesskey, cmid);
+}
diff --git a/mod/scorm/datamodels/aicc.php b/mod/scorm/datamodels/aicc.php
new file mode 100644 (file)
index 0000000..17839ac
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+require_once($CFG->dirroot.'/mod/scorm/locallib.php');
+
+$userdata = new stdClass();
+$def = get_scorm_default($userdata, $scorm, $scoid, $attempt, $mode);
+
+if (!isset($currentorg)) {
+    $currentorg = '';
+}
+
+$cmiobj = '';
+$currentobj = '';
+$count = 0;
+foreach ($userdata as $element => $value) {
+    if (substr($element, 0, 14) == 'cmi.objectives') {
+        $element = preg_replace('/\.(\d+)\./', "_\$1.", $element);
+        preg_match('/\_(\d+)\./', $element, $matches);
+        if (count($matches) > 0 && $currentobj != $matches[1]) {
+            $currentobj = $matches[1];
+            $count++;
+            $end = strpos($element, $matches[1])+strlen($matches[1]);
+            $subelement = substr($element, 0, $end);
+            $cmiobj .= '    '.$subelement." = new Object();\n";
+            $cmiobj .= '    '.$subelement.".score = new Object();\n";
+            $cmiobj .= '    '.$subelement.".score._children = score_children;\n";
+            $cmiobj .= '    '.$subelement.".score.raw = '';\n";
+            $cmiobj .= '    '.$subelement.".score.min = '';\n";
+            $cmiobj .= '    '.$subelement.".score.max = '';\n";
+        }
+        $cmiobj .= '    '.$element.' = \''.$value."';\n";
+    }
+}
+if ($count > 0) {
+    $cmiobj .= '    cmi.objectives._count = '.$count.";\n";
+}
+
+$PAGE->requires->js_init_call('M.scorm_api.init', array($def, $cmiobj, $scorm->auto, $CFG->wwwroot, $scorm->id, $scoid, $attempt,
+                                                         $mode, $currentorg, sesskey(), $id));
index da1ef1c..5015a25 100644 (file)
@@ -118,7 +118,6 @@ function scorm_forge_cols_regexp($columns, $remodule='(".*")?,') {
  * Sets up AICC packages
  * Called whenever package changes
  * @param object $scorm instance - fields are updated and changes saved into database
-
  * @return bool
  */
 function scorm_parse_aicc(&$scorm) {
@@ -478,4 +477,88 @@ function scorm_aicc_generate_simple_sco($scorm) {
         $id = $DB->insert_record('scorm_scoes', $sco);
     }
     return $id;
-}
\ No newline at end of file
+}
+
+/**
+ * Sets up $userdata array and default values for AICC package.
+ *
+ * @param stdClass $userdata an empty stdClass variable that should be set up with user values
+ * @param object $scorm package record
+ * @param string $scoid SCO Id
+ * @param string $attempt attempt number for the user
+ * @param string $mode scorm display mode type
+ * @return array The default values that should be used for AICC package
+ */
+function get_scorm_default (&$userdata, $scorm, $scoid, $attempt, $mode) {
+    global $USER;
+
+    $userdata->student_id = $USER->username;
+    $userdata->student_name = $USER->lastname .', '. $USER->firstname;
+
+    if ($usertrack = scorm_get_tracks($scoid, $USER->id, $attempt)) {
+        foreach ($usertrack as $key => $value) {
+            $userdata->$key = $value;
+        }
+    } else {
+        $userdata->status = '';
+        $userdata->score_raw = '';
+    }
+
+    if ($scodatas = scorm_get_sco($scoid, SCO_DATA)) {
+        foreach ($scodatas as $key => $value) {
+            $userdata->$key = $value;
+        }
+    } else {
+        print_error('cannotfindsco', 'scorm');
+    }
+    if (!$sco = scorm_get_sco($scoid)) {
+        print_error('cannotfindsco', 'scorm');
+    }
+
+    $userdata->mode = 'normal';
+    if (!empty($mode)) {
+        $userdata->mode = $mode;
+    }
+    if ($userdata->mode == 'normal') {
+        $userdata->credit = 'credit';
+    } else {
+        $userdata->credit = 'no-credit';
+    }
+
+    if (isset($userdata->status)) {
+        if ($userdata->status == '') {
+            $userdata->entry = 'ab-initio';
+        } else {
+            if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {
+                $userdata->entry = 'resume';
+            } else {
+                $userdata->entry = '';
+            }
+        }
+    }
+
+    $def = array();
+    $def['cmi.core.student_id'] = $userdata->student_id;
+    $def['cmi.core.student_name'] = $userdata->student_name;
+    $def['cmi.core.credit'] = $userdata->credit;
+    $def['cmi.core.entry'] = $userdata->entry;
+    $def['cmi.launch_data'] = scorm_isset($userdata, 'datafromlms');
+    $def['cmi.core.lesson_mode'] = $userdata->mode;
+    $def['cmi.student_data.attempt_number'] = scorm_isset($userdata, 'cmi.student_data.attempt_number');
+    $def['cmi.student_data.mastery_score'] = scorm_isset($userdata, 'mastery_score');
+    $def['cmi.student_data.max_time_allowed'] = scorm_isset($userdata, 'max_time_allowed');
+    $def['cmi.student_data.time_limit_action'] = scorm_isset($userdata, 'time_limit_action');
+    $def['cmi.student_data.tries_during_lesson'] = scorm_isset($userdata, 'cmi.student_data.tries_during_lesson');
+
+    $def['cmi.core.lesson_location'] = scorm_isset($userdata, 'cmi.core.lesson_location');
+    $def['cmi.core.lesson_status'] = scorm_isset($userdata, 'cmi.core.lesson_status');
+    $def['cmi.core.exit'] = scorm_isset($userdata, 'cmi.core.exit');
+    $def['cmi.core.score.raw'] = scorm_isset($userdata, 'cmi.core.score.raw');
+    $def['cmi.core.score.max'] = scorm_isset($userdata, 'cmi.core.score.max');
+    $def['cmi.core.score.min'] = scorm_isset($userdata, 'cmi.core.score.min');
+    $def['cmi.core.total_time'] = scorm_isset($userdata, 'cmi.core.total_time', '00:00:00');
+    $def['cmi.suspend_data'] = scorm_isset($userdata, 'cmi.suspend_data');
+    $def['cmi.comments'] = scorm_isset($userdata, 'cmi.comments');
+
+    return $def;
+}
index 9011ab9..771ef76 100644 (file)
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
+echo html_writer::start_tag('script');
 ?>
 
 <!--// hopefully fool ie IE proof way of getting DOM element
@@ -70,7 +71,7 @@ function toggleLog () {
     if (getLoggingActive() == "A") {
         AppendToLog("Moodle Logging Deactivated", 0);
         setLoggingActive('N');
-        logButton.innerHTML = '--><?php echo addslashes_js(get_string('scormloggingoff', 'scorm')); ?>';
+        logButton.innerHTML = '-><?php echo addslashes_js(get_string('scormloggingoff', 'scorm')); ?>';
     } else {
         setLoggingActive('A');
         AppendToLog("Moodle Logging Activated", 0);
@@ -762,3 +763,7 @@ if (!document.getElementById('mod-scorm-log-toggle')) {
     var content = safeGetElement(document, 'scormpage');
     content.insertBefore(logButton, content.firstChild);
 }
+-->
+
+<?php
+echo html_writer::end_tag('script');
similarity index 75%
rename from mod/scorm/datamodels/scorm_12.js.php
rename to mod/scorm/datamodels/scorm_12.js
index da262c2..44ac498 100644 (file)
@@ -1,4 +1,3 @@
-<?php
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-require_once($CFG->dirroot.'/mod/scorm/locallib.php');
-
-if (isset($userdata->status)) {
-    if ($userdata->status == '') {
-        $userdata->entry = 'ab-initio';
-    } else {
-        if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {
-            $userdata->entry = 'resume';
-        } else {
-            $userdata->entry = '';
-        }
-    }
-}
-if (!isset($currentorg)) {
-    $currentorg = '';
-}
-
-// If SCORM 1.2 standard mode is disabled allow higher datamodel limits.
-if (intval(get_config("scorm", "scorm12standard"))) {
-    $cmistring256 = '^[\\u0000-\\uFFFF]{0,255}$';
-    $cmistring4096 = '^[\\u0000-\\uFFFF]{0,4096}$';
-} else {
-    $cmistring256 = '^[\\u0000-\\uFFFF]{0,64000}$';
-    $cmistring4096 = $cmistring256;
-}
-?>
 //
 // SCORM 1.2 API Implementation
 //
-function SCORMapi1_2() {
+function SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebugging, scormauto, scormid, cfgwwwroot, sesskey, scoid, attempt, viewmode, cmid, currentorg) {
+
+    var prerequrl = cfgwwwroot + "/mod/scorm/prereqs.php?a="+scormid+"&scoid="+scoid+"&attempt="+attempt+"&mode="+viewmode+"&currentorg="+currentorg+"&sesskey="+sesskey;
+    var datamodelurl = cfgwwwroot + "/mod/scorm/datamodel.php";
+    var datamodelurlparams = "id="+cmid+"&a="+scormid+"&sesskey="+sesskey+"&attempt="+attempt+"&scoid="+scoid;
+
     // Standard Data Type Definition
-    CMIString256 = '<?php echo $cmistring256 ?>';
-    CMIString4096 = '<?php echo $cmistring4096 ?>';
+    CMIString256 = cmistring256;
+    CMIString4096 = cmistring4096;
     CMITime = '^([0-2]{1}[0-9]{1}):([0-5]{1}[0-9]{1}):([0-5]{1}[0-9]{1})(\.[0-9]{1,2})?$';
     CMITimespan = '^([0-9]{2,4}):([0-9]{2}):([0-9]{2})(\.[0-9]{1,2})?$';
     CMIInteger = '^\\d+$';
@@ -83,23 +61,23 @@ function SCORMapi1_2() {
         'cmi._children':{'defaultvalue':cmi_children, 'mod':'r', 'writeerror':'402'},
         'cmi._version':{'defaultvalue':'3.4', 'mod':'r', 'writeerror':'402'},
         'cmi.core._children':{'defaultvalue':core_children, 'mod':'r', 'writeerror':'402'},
-        'cmi.core.student_id':{'defaultvalue':'<?php echo $userdata->student_id ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.core.student_name':{'defaultvalue':'<?php echo $userdata->student_name ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.core.lesson_location':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.lesson_location'})?$userdata->{'cmi.core.lesson_location'}:'' ?>', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
-        'cmi.core.credit':{'defaultvalue':'<?php echo $userdata->credit ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.core.lesson_status':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.lesson_status'})?$userdata->{'cmi.core.lesson_status'}:'' ?>', 'format':CMIStatus, 'mod':'rw', 'writeerror':'405'},
-        'cmi.core.entry':{'defaultvalue':'<?php echo $userdata->entry ?>', 'mod':'r', 'writeerror':'403'},
+        'cmi.core.student_id':{'defaultvalue':def['cmi.core.student_id'], 'mod':'r', 'writeerror':'403'},
+        'cmi.core.student_name':{'defaultvalue':def['cmi.core.student_name'], 'mod':'r', 'writeerror':'403'},
+        'cmi.core.lesson_location':{'defaultvalue':def['cmi.core.lesson_location'], 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
+        'cmi.core.credit':{'defaultvalue':def['cmi.core.credit'], 'mod':'r', 'writeerror':'403'},
+        'cmi.core.lesson_status':{'defaultvalue':def['cmi.core.lesson_status'], 'format':CMIStatus, 'mod':'rw', 'writeerror':'405'},
+        'cmi.core.entry':{'defaultvalue':def['cmi.core.entry'], 'mod':'r', 'writeerror':'403'},
         'cmi.core.score._children':{'defaultvalue':score_children, 'mod':'r', 'writeerror':'402'},
-        'cmi.core.score.raw':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.raw'})?$userdata->{'cmi.core.score.raw'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
-        'cmi.core.score.max':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.max'})?$userdata->{'cmi.core.score.max'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
-        'cmi.core.score.min':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.score.min'})?$userdata->{'cmi.core.score.min'}:'' ?>', 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
-        'cmi.core.total_time':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.total_time'})?$userdata->{'cmi.core.total_time'}:'00:00:00' ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.core.lesson_mode':{'defaultvalue':'<?php echo $userdata->mode ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.core.exit':{'defaultvalue':'<?php echo isset($userdata->{'cmi.core.exit'})?$userdata->{'cmi.core.exit'}:'' ?>', 'format':CMIExit, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
+        'cmi.core.score.raw':{'defaultvalue':def['cmi.core.score.raw'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
+        'cmi.core.score.max':{'defaultvalue':def['cmi.core.score.max'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
+        'cmi.core.score.min':{'defaultvalue':def['cmi.core.score.min'], 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
+        'cmi.core.total_time':{'defaultvalue':def['cmi.core.total_time'], 'mod':'r', 'writeerror':'403'},
+        'cmi.core.lesson_mode':{'defaultvalue':def['cmi.core.lesson_mode'], 'mod':'r', 'writeerror':'403'},
+        'cmi.core.exit':{'defaultvalue':def['cmi.core.exit'], 'format':CMIExit, 'mod':'w', 'readerror':'404', 'writeerror':'405'},
         'cmi.core.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'00:00:00', 'readerror':'404', 'writeerror':'405'},
-        'cmi.suspend_data':{'defaultvalue':'<?php echo isset($userdata->{'cmi.suspend_data'})?$userdata->{'cmi.suspend_data'}:'' ?>', 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
-        'cmi.launch_data':{'defaultvalue':'<?php echo isset($userdata->datafromlms)?$userdata->datafromlms:'' ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.comments':{'defaultvalue':'<?php echo isset($userdata->{'cmi.comments'})?$userdata->{'cmi.comments'}:'' ?>', 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
+        'cmi.suspend_data':{'defaultvalue':def['cmi.suspend_data'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
+        'cmi.launch_data':{'defaultvalue':def['cmi.launch_data'], 'mod':'r', 'writeerror':'403'},
+        'cmi.comments':{'defaultvalue':def['cmi.comments'], 'format':CMIString4096, 'mod':'rw', 'writeerror':'405'},
         // deprecated evaluation attributes
         'cmi.evaluation.comments._count':{'defaultvalue':'0', 'mod':'r', 'writeerror':'402'},
         'cmi.evaluation.comments._children':{'defaultvalue':comments_children, 'mod':'r', 'writeerror':'402'},
@@ -116,9 +94,9 @@ function SCORMapi1_2() {
         'cmi.objectives.n.score.max':{'defaultvalue':'', 'pattern':CMIIndex, 'format':CMIDecimal, 'range':score_range, 'mod':'rw', 'writeerror':'405'},
         'cmi.objectives.n.status':{'pattern':CMIIndex, 'format':CMIStatus2, 'mod':'rw', 'writeerror':'405'},
         'cmi.student_data._children':{'defaultvalue':student_data_children, 'mod':'r', 'writeerror':'402'},
-        'cmi.student_data.mastery_score':{'defaultvalue':'<?php echo isset($userdata->masteryscore)?$userdata->masteryscore:'' ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.student_data.max_time_allowed':{'defaultvalue':'<?php echo isset($userdata->maxtimeallowed)?$userdata->maxtimeallowed:'' ?>', 'mod':'r', 'writeerror':'403'},
-        'cmi.student_data.time_limit_action':{'defaultvalue':'<?php echo isset($userdata->timelimitaction)?$userdata->timelimitaction:'' ?>', 'mod':'r', 'writeerror':'403'},
+        'cmi.student_data.mastery_score':{'defaultvalue':def['cmi.student_data.mastery_score'], 'mod':'r', 'writeerror':'403'},
+        'cmi.student_data.max_time_allowed':{'defaultvalue':def['cmi.student_data.max_time_allowed'], 'mod':'r', 'writeerror':'403'},
+        'cmi.student_data.time_limit_action':{'defaultvalue':def['cmi.student_data.time_limit_action'], 'mod':'r', 'writeerror':'403'},
         'cmi.student_preference._children':{'defaultvalue':student_preference_children, 'mod':'r', 'writeerror':'402'},
         'cmi.student_preference.audio':{'defaultvalue':'0', 'format':CMISInteger, 'range':audio_range, 'mod':'rw', 'writeerror':'405'},
         'cmi.student_preference.language':{'defaultvalue':'', 'format':CMIString256, 'mod':'rw', 'writeerror':'405'},
@@ -166,11 +144,8 @@ function SCORMapi1_2() {
         }
     }
 
-<?php
-     // reconstitute objectives
-    scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.objectives', array('score'));
-    scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.interactions', array('objectives', 'correct_responses'));
-    ?>
+    eval(cmiobj);
+    eval(cmiint);
 
     if (cmi.core.lesson_status == '') {
         cmi.core.lesson_status = 'not attempted';
@@ -187,11 +162,9 @@ function SCORMapi1_2() {
             if (!Initialized) {
                 Initialized = true;
                 errorCode = "0";
-                <?php
-                    if (scorm_debugging($scorm)) {
-                        echo 'LogAPICall("LMSInitialize", param, "", errorCode);';
-                    }
-                ?>
+                if (scormdebugging) {
+                    LogAPICall("LMSInitialize", param, "", errorCode);
+                }
                 return "true";
             } else {
                 errorCode = "101";
@@ -199,11 +172,9 @@ function SCORMapi1_2() {
         } else {
             errorCode = "201";
         }
-        <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("LMSInitialize", param, "", errorCode);';
-            }
-        ?>
+        if (scormdebugging) {
+            LogAPICall("LMSInitialize", param, "", errorCode);
+        }
         return "false";
     }
 
@@ -220,29 +191,24 @@ function SCORMapi1_2() {
                         setTimeout('mod_scorm_launch_prev_sco();',500);
                     }
                 } else {
-                    if (<?php echo $scorm->auto ?> == 1) {
+                    if (scormauto == 1) {
                         setTimeout('mod_scorm_launch_next_sco();',500);
                     }
                 }
-                <?php
-                    if (scorm_debugging($scorm)) {
-                        echo 'LogAPICall("LMSFinish", "AJAXResult", result, 0);';
-                    }
-                ?>
+                if (scormdebugging) {
+                    LogAPICall("LMSFinish", "AJAXResult", result, 0);
+                }
                 result = ('true' == result) ? 'true' : 'false';
                 errorCode = (result == 'true')? '0' : '101';
-                <?php
-                    if (scorm_debugging($scorm)) {
-                        echo 'LogAPICall("LMSFinish", "result", result, 0);';
-                        echo 'LogAPICall("LMSFinish", param, "", 0);';
-                    }
-                ?>
+                if (scormdebugging) {
+                    LogAPICall("LMSFinish", "result", result, 0);
+                    LogAPICall("LMSFinish", param, "", 0);
+                }
                 // trigger TOC update
-                var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
                 var callback = M.mod_scorm.connectPrereqCallback;
                 YUI().use('io-base', function(Y) {
                     Y.on('io:complete', callback.success, Y);
-                    Y.io(sURL);
+                    Y.io(prerequrl);
                 });
                 return result;
             } else {
@@ -251,11 +217,9 @@ function SCORMapi1_2() {
         } else {
             errorCode = "201";
         }
-        <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("LMSFinish", param, "", errorCode);';
-            }
-        ?>
+        if (scormdebugging) {
+            LogAPICall("LMSFinish", param, "", errorCode);
+        }
         return "false";
     }
 
@@ -276,11 +240,9 @@ function SCORMapi1_2() {
                         }
                             if (subelement == element) {
                             errorCode = "0";
-                            <?php
-                                if (scorm_debugging($scorm)) {
-                                    echo 'LogAPICall("LMSGetValue", element, eval(element), 0);';
-                                }
-                            ?>
+                            if (scormdebugging) {
+                                LogAPICall("LMSGetValue", element, eval(element), 0);
+                            }
                             return eval(element);
                         } else {
                             errorCode = "0"; // Need to check if it is the right errorCode
@@ -315,11 +277,9 @@ function SCORMapi1_2() {
         } else {
             errorCode = "301";
         }
-        <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("LMSGetValue", element, "", errorCode);';
-            }
-        ?>
+        if (scormdebugging) {
+            LogAPICall("LMSGetValue", element, "", errorCode);
+        }
         return "";
     }
 
@@ -385,11 +345,9 @@ function SCORMapi1_2() {
                                     if ((value >= ranges[0]) && (value <= ranges[1])) {
                                         eval(element+'=value;');
                                         errorCode = "0";
-                                        <?php
-                                            if (scorm_debugging($scorm)) {
-                                                echo 'LogAPICall("LMSSetValue", element, value, errorCode);';
-                                            }
-                                        ?>
+                                        if (scormdebugging) {
+                                            LogAPICall("LMSSetValue", element, value, errorCode);
+                                        }
                                         return "true";
                                     } else {
                                         errorCode = eval('datamodel["'+elementmodel+'"].writeerror');
@@ -401,11 +359,9 @@ function SCORMapi1_2() {
                                         eval(element+'=value;');
                                     }
                                     errorCode = "0";
-                                    <?php
-                                        if (scorm_debugging($scorm)) {
-                                            echo 'LogAPICall("LMSSetValue", element, value, errorCode);';
-                                        }
-                                    ?>
+                                    if (scormdebugging) {
+                                        LogAPICall("LMSSetValue", element, value, errorCode);
+                                    }
                                     return "true";
                                 }
                             }
@@ -424,11 +380,9 @@ function SCORMapi1_2() {
         } else {
             errorCode = "301";
         }
-       <?php
-        if (scorm_debugging($scorm)) {
-            echo 'LogAPICall("LMSSetValue", element, value, errorCode);';
+        if (scormdebugging) {
+            LogAPICall("LMSSetValue", element, value, errorCode);
         }
-        ?>
         return "false";
     }
 
@@ -438,30 +392,23 @@ function SCORMapi1_2() {
             if (Initialized) {
                 result = StoreData(cmi,false);
                 // trigger TOC update
-                var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
                 var callback = M.mod_scorm.connectPrereqCallback;
                 YUI().use('io-base', function(Y) {
                     Y.on('io:complete', callback.success, Y);
-                    Y.io(sURL);
+                    Y.io(prerequrl);
                 });
-                <?php
-                    if (scorm_debugging($scorm)) {
-                        echo 'LogAPICall("Commit", param, "", 0);';
-                    }
-                ?>
-                <?php
-                    if (scorm_debugging($scorm)) {
-                        echo 'LogAPICall("LMSCommit", "AJAXResult", result, 0);';
-                    }
-                ?>
+                if (scormdebugging) {
+                    LogAPICall("Commit", param, "", 0);
+                }
+                if (scormdebugging) {
+                    LogAPICall("LMSCommit", "AJAXResult", result, 0);
+                }
                 result = ('true' == result) ? 'true' : 'false';
                 errorCode = (result =='true')? '0' : '101';
-                <?php
-                    if (scorm_debugging($scorm)) {
-                        echo 'LogAPICall("LMSCommit", "result", result, 0);';
-                        echo 'LogAPICall("LMSCommit", "errorCode", errorCode, 0);';
-                    }
-                ?>
+                if (scormdebugging) {
+                    LogAPICall("LMSCommit", "result", result, 0);
+                    LogAPICall("LMSCommit", "errorCode", errorCode, 0);
+                }
                 return result;
             } else {
                 errorCode = "301";
@@ -469,20 +416,16 @@ function SCORMapi1_2() {
         } else {
             errorCode = "201";
         }
-        <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("LMSCommit", param, "", 0);';
-            }
-        ?>
+        if (scormdebugging) {
+            LogAPICall("LMSCommit", param, "", 0);
+        }
         return "false";
     }
 
     function LMSGetLastError () {
-     <?php
-        if (scorm_debugging($scorm)) {
-            echo 'LogAPICall("LMSGetLastError", "", "", errorCode);';
+        if (scormdebugging) {
+            LogAPICall("LMSGetLastError", "", "", errorCode);
         }
-    ?>
         return errorCode;
     }
 
@@ -500,18 +443,14 @@ function SCORMapi1_2() {
             errorString["403"] = "Element is read only";
             errorString["404"] = "Element is write only";
             errorString["405"] = "Incorrect data type";
-            <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("LMSGetErrorString", param,  errorString[param], 0);';
+            if (scormdebugging) {
+                LogAPICall("LMSGetErrorString", param,  errorString[param], 0);
             }
-             ?>
             return errorString[param];
         } else {
-           <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("LMSGetErrorString", param,  "No error string found!", 0);';
+            if (scormdebugging) {
+                LogAPICall("LMSGetErrorString", param,  "No error string found!", 0);
             }
-             ?>
            return "";
         }
     }
@@ -520,11 +459,9 @@ function SCORMapi1_2() {
         if (param == "") {
             param = errorCode;
         }
-        <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("LMSGetDiagnostic", param, param, 0);';
-            }
-        ?>
+        if (scormdebugging) {
+            LogAPICall("LMSGetDiagnostic", param, param, 0);
+        }
         return param;
     }
 
@@ -680,12 +617,10 @@ function SCORMapi1_2() {
         } else {
             datastring = CollectData(data,'cmi');
         }
-        datastring += '&attempt=<?php echo $attempt ?>';
-        datastring += '&scoid=<?php echo $scoid ?>';
 
         var myRequest = NewHttpReq();
         //alert('going to:' + "<?php p($CFG->wwwroot) ?>/mod/scorm/datamodel.php" + "id=<?php p($id) ?>&a=<?php p($a) ?>&sesskey=<?php echo sesskey() ?>"+datastring);
-        result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/datamodel.php","id=<?php p($id) ?>&a=<?php p($a) ?>&sesskey=<?php echo sesskey() ?>"+datastring);
+        result = DoRequest(myRequest,datamodelurl,datamodelurlparams+datastring);
         results = String(result).split('\n');
         errorCode = results[1];
         return results[0];
@@ -701,12 +636,8 @@ function SCORMapi1_2() {
     this.LMSGetDiagnostic = LMSGetDiagnostic;
 }
 
-var API = new SCORMapi1_2();
+M.scorm_api = {};
 
-<?php
-// pull in the debugging utilities
-if (scorm_debugging($scorm)) {
-    include_once($CFG->dirroot.'/mod/scorm/datamodels/debug.js.php');
-    echo 'AppendToLog("Moodle SCORM 1.2 API Loaded, Activity: '.$scorm->name.', SCO: '.$sco->identifier.'", 0);';
+M.scorm_api.init = function(Y, def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebugging, scormauto, scormid, cfgwwwroot, sesskey, scoid, attempt, viewmode, cmid, currentorg) {
+    window.API = new SCORMapi1_2(def, cmiobj, cmiint, cmistring256, cmistring4096, scormdebugging, scormauto, scormid, cfgwwwroot, sesskey, scoid, attempt, viewmode, cmid, currentorg);
 }
-
diff --git a/mod/scorm/datamodels/scorm_12.php b/mod/scorm/datamodels/scorm_12.php
new file mode 100644 (file)
index 0000000..187fd62
--- /dev/null
@@ -0,0 +1,48 @@
+<?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/>.
+
+require_once($CFG->dirroot.'/mod/scorm/locallib.php');
+
+// Set some vars to use as default values.
+$userdata = new stdClass();
+$def = get_scorm_default($userdata, $scorm, $scoid, $attempt, $mode);
+
+if (!isset($currentorg)) {
+    $currentorg = '';
+}
+
+// If SCORM 1.2 standard mode is disabled allow higher datamodel limits.
+if (intval(get_config("scorm", "scorm12standard"))) {
+    $cmistring256 = '^[\\u0000-\\uFFFF]{0,255}$';
+    $cmistring4096 = '^[\\u0000-\\uFFFF]{0,4096}$';
+} else {
+    $cmistring256 = '^[\\u0000-\\uFFFF]{0,64000}$';
+    $cmistring4096 = $cmistring256;
+}
+
+// reconstitute objectives
+$cmiobj = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.objectives', array('score'));
+$cmiint = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.interactions', array('objectives', 'correct_responses'));
+
+$PAGE->requires->js_init_call('M.scorm_api.init', array($def, $cmiobj, $cmiint, $cmistring256, $cmistring4096,
+                                                        scorm_debugging($scorm), $scorm->auto, $scorm->id, $CFG->wwwroot,
+                                                        sesskey(), $scoid, $attempt, $mode, $id, $currentorg));
+
+// pull in the debugging utilities
+if (scorm_debugging($scorm)) {
+    require_once($CFG->dirroot.'/mod/scorm/datamodels/debug.js.php');
+    echo html_writer::script('AppendToLog("Moodle SCORM 1.2 API Loaded, Activity: '.$scorm->name.', SCO: '.$sco->identifier.'", 0);');
+}
\ No newline at end of file
index 68ab951..ec3be06 100644 (file)
@@ -120,3 +120,89 @@ function scorm_eval_prerequisites($prerequisites, $usertracks) {
     }
     return eval('return '.implode($stack).';');
 }
+
+/**
+ * Sets up $userdata array and default values for SCORM 1.2 .
+ *
+ * @param stdClass $userdata an empty stdClass variable that should be set up with user values
+ * @param object $scorm package record
+ * @param string $scoid SCO Id
+ * @param string $attempt attempt number for the user
+ * @param string $mode scorm display mode type
+ * @return array The default values that should be used for SCORM 1.2 package
+ */
+function get_scorm_default (&$userdata, $scorm, $scoid, $attempt, $mode) {
+    global $USER;
+
+    $userdata->student_id = $USER->username;
+    $userdata->student_name = $USER->lastname .', '. $USER->firstname;
+
+    if ($usertrack = scorm_get_tracks($scoid, $USER->id, $attempt)) {
+        foreach ($usertrack as $key => $value) {
+            $userdata->$key = $value;
+        }
+    } else {
+        $userdata->status = '';
+        $userdata->score_raw = '';
+    }
+
+    if ($scodatas = scorm_get_sco($scoid, SCO_DATA)) {
+        foreach ($scodatas as $key => $value) {
+            $userdata->$key = $value;
+        }
+    } else {
+        print_error('cannotfindsco', 'scorm');
+    }
+    if (!$sco = scorm_get_sco($scoid)) {
+        print_error('cannotfindsco', 'scorm');
+    }
+
+    if (isset($userdata->status)) {
+        if ($userdata->status == '') {
+            $userdata->entry = 'ab-initio';
+        } else {
+            if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {
+                $userdata->entry = 'resume';
+            } else {
+                $userdata->entry = '';
+            }
+        }
+    }
+
+    $userdata->mode = 'normal';
+    if (!empty($mode)) {
+        $userdata->mode = $mode;
+    }
+    if ($userdata->mode == 'normal') {
+        $userdata->credit = 'credit';
+    } else {
+        $userdata->credit = 'no-credit';
+    }
+
+    $def = array();
+    $def['cmi.core.student_id'] = $userdata->student_id;
+    $def['cmi.core.student_name'] = $userdata->student_name;
+    $def['cmi.core.credit'] = $userdata->credit;
+    $def['cmi.core.entry'] = $userdata->entry;
+    $def['cmi.core.lesson_mode'] = $userdata->mode;
+    $def['cmi.launch_data'] = scorm_isset($userdata, 'datafromlms');
+    $def['cmi.student_data.mastery_score'] = scorm_isset($userdata, 'masteryscore');
+    $def['cmi.student_data.max_time_allowed'] = scorm_isset($userdata, 'maxtimeallowed');
+    $def['cmi.student_data.time_limit_action'] = scorm_isset($userdata, 'timelimitaction');
+    $def['cmi.core.total_time'] = scorm_isset($userdata, 'cmi.core.total_time', '00:00:00');
+
+    // Now handle standard userdata items:
+    $def['cmi.core.lesson_location'] = scorm_isset($userdata, 'cmi.core.lesson_location');
+    $def['cmi.core.lesson_status'] = scorm_isset($userdata, 'cmi.core.lesson_status');
+    $def['cmi.core.score.raw'] = scorm_isset($userdata, 'cmi.core.score.raw');
+    $def['cmi.core.score.max'] = scorm_isset($userdata, 'cmi.core.score.max');
+    $def['cmi.core.score.min'] = scorm_isset($userdata, 'cmi.core.score.min');
+    $def['cmi.core.exit'] = scorm_isset($userdata, 'cmi.core.exit');
+    $def['cmi.suspend_data'] = scorm_isset($userdata, 'cmi.suspend_data');
+    $def['cmi.comments'] = scorm_isset($userdata, 'cmi.comments');
+    $def['cmi.student_preference.language'] = scorm_isset($userdata, 'cmi.student_preference.language');
+    $def['cmi.student_preference.audio'] = scorm_isset($userdata, 'cmi.student_preference.audio', '0');
+    $def['cmi.student_preference.speed'] = scorm_isset($userdata, 'cmi.student_preference.speed', '0');
+    $def['cmi.student_preference.text'] = scorm_isset($userdata, 'cmi.student_preference.text', '0');
+    return $def;
+}
similarity index 87%
rename from mod/scorm/datamodels/scorm_13.js.php
rename to mod/scorm/datamodels/scorm_13.js
index 44240c6..9756206 100644 (file)
@@ -1,4 +1,3 @@
-<?php
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-require_once($CFG->dirroot.'/mod/scorm/locallib.php');
-
-if (isset($userdata->status)) {
-    if (!isset($userdata->{'cmi.exit'}) || (($userdata->{'cmi.exit'} == 'time-out') || ($userdata->{'cmi.exit'} == 'normal'))) {
-            $userdata->entry = 'ab-initio';
-    } else {
-        if (isset($userdata->{'cmi.exit'}) && (($userdata->{'cmi.exit'} == 'suspend') || ($userdata->{'cmi.exit'} == 'logout'))) {
-            $userdata->entry = 'resume';
-        } else {
-            $userdata->entry = '';
-        }
-    }
-}
-if (!isset($currentorg)) {
-    $currentorg = '';
-}
-?>
-
 // Used need to debug cmi content (if you uncomment this, you must comment the definition inside SCORMapi1_3)
 //var cmi = new Object();
 
 //
 // SCORM 1.3 API Implementation
 //
-function SCORMapi1_3() {
+function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scormdebugging, scormauto, scormid, cfgwwwroot, sesskey, scoid, attempt, viewmode, cmid, currentorg) {
+
+    var prerequrl = cfgwwwroot + "/mod/scorm/prereqs.php?a="+scormid+"&scoid="+scoid+"&attempt="+attempt+"&mode="+viewmode+"&currentorg="+currentorg+"&sesskey="+sesskey;
+    var datamodelurl = cfgwwwroot + "/mod/scorm/datamodel.php";
+    var datamodelurlparams = "id="+cmid+"&a="+scormid+"&sesskey="+sesskey+"&attempt="+attempt+"&scoid="+scoid;
+
     // Standard Data Type Definition
 
     // language key has to be checked for language dependent strings
@@ -177,11 +163,11 @@ function SCORMapi1_3() {
         'cmi.comments_from_lms.n.comment':{'format':CMILangString4000, 'mod':'r'},
         'cmi.comments_from_lms.n.location':{'format':CMIString250, 'mod':'r'},
         'cmi.comments_from_lms.n.timestamp':{'format':CMITime, 'mod':'r'},
-        'cmi.completion_status':{'defaultvalue':'<?php echo !empty($userdata->{'cmi.completion_status'})?$userdata->{'cmi.completion_status'}:'unknown' ?>', 'format':CMICStatus, 'mod':'rw'},
-        'cmi.completion_threshold':{'defaultvalue':<?php echo !empty($userdata->threshold)?'\''.$userdata->threshold.'\'':'null' ?>, 'mod':'r'},
-        'cmi.credit':{'defaultvalue':'<?php echo !empty($userdata->credit)?$userdata->credit:'' ?>', 'mod':'r'},
-        'cmi.entry':{'defaultvalue':'<?php echo $userdata->entry ?>', 'mod':'r'},
-        'cmi.exit':{'defaultvalue':'<?php echo !empty($userdata->{'cmi.exit'})?$userdata->{'cmi.exit'}:'' ?>', 'format':CMIExit, 'mod':'w'},
+        'cmi.completion_status':{'defaultvalue':def['cmi.completion_status'], 'format':CMICStatus, 'mod':'rw'},
+        'cmi.completion_threshold':{'defaultvalue':def['cmi.completion_threshold'], 'mod':'r'},
+        'cmi.credit':{'defaultvalue':def['cmi.credit'], 'mod':'r'},
+        'cmi.entry':{'defaultvalue':def['cmi.entry'], 'mod':'r'},
+        'cmi.exit':{'defaultvalue':def['cmi.exit'], 'format':CMIExit, 'mod':'w'},
         'cmi.interactions._children':{'defaultvalue':interactions_children, 'mod':'r'},
         'cmi.interactions._count':{'mod':'r', 'defaultvalue':'0'},
         'cmi.interactions.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'},
@@ -196,17 +182,17 @@ function SCORMapi1_3() {
         'cmi.interactions.n.result':{'pattern':CMIIndex, 'format':CMIResult, 'mod':'rw'},
         'cmi.interactions.n.latency':{'pattern':CMIIndex, 'format':CMITimespan, 'mod':'rw'},
         'cmi.interactions.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'},
-        'cmi.launch_data':{'defaultvalue':<?php echo !empty($userdata->datafromlms)?'\''.$userdata->datafromlms.'\'':'null' ?>, 'mod':'r'},
-        'cmi.learner_id':{'defaultvalue':'<?php echo $userdata->student_id ?>', 'mod':'r'},
-        'cmi.learner_name':{'defaultvalue':'<?php echo $userdata->student_name ?>', 'mod':'r'},
+        'cmi.launch_data':{'defaultvalue':def['cmi.exit'], 'mod':'r'},
+        'cmi.learner_id':{'defaultvalue':def['cmi.learner_id'], 'mod':'r'},
+        'cmi.learner_name':{'defaultvalue':def['cmi.learner_name'], 'mod':'r'},
         'cmi.learner_preference._children':{'defaultvalue':student_preference_children, 'mod':'r'},
-        'cmi.learner_preference.audio_level':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.audio_level'})?'\''.$userdata->{'cmi.learner_preference.audio_level'}.'\'':'\'1\'' ?>, 'format':CMIDecimal, 'range':audio_range, 'mod':'rw'},
-        'cmi.learner_preference.language':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.language'})?'\''.$userdata->{'cmi.learner_preference.language'}.'\'':'\'\'' ?>, 'format':CMILang, 'mod':'rw'},
-        'cmi.learner_preference.delivery_speed':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.delivery_speed'})?'\''.$userdata->{'cmi.learner_preference.delivery_speed'}.'\'':'\'1\'' ?>, 'format':CMIDecimal, 'range':speed_range, 'mod':'rw'},
-        'cmi.learner_preference.audio_captioning':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.audio_captioning'})?'\''.$userdata->{'cmi.learner_preference.audio_captioning'}.'\'':'\'0\'' ?>, 'format':CMISInteger, 'range':text_range, 'mod':'rw'},
-        'cmi.location':{'defaultvalue':<?php echo !empty($userdata->{'cmi.location'})?'\''.$userdata->{'cmi.location'}.'\'':'null' ?>, 'format':CMIString1000, 'mod':'rw'},
-        'cmi.max_time_allowed':{'defaultvalue':<?php echo !empty($userdata->attemptAbsoluteDurationLimit)?'\''.$userdata->attemptAbsoluteDurationLimit.'\'':'null' ?>, 'mod':'r'},
-        'cmi.mode':{'defaultvalue':'<?php echo $userdata->mode ?>', 'mod':'r'},
+        'cmi.learner_preference.audio_level':{'defaultvalue':def['cmi.learner_preference.audio_level'], 'format':CMIDecimal, 'range':audio_range, 'mod':'rw'},
+        'cmi.learner_preference.language':{'defaultvalue':def['cmi.learner_preference.language'], 'format':CMILang, 'mod':'rw'},
+        'cmi.learner_preference.delivery_speed':{'defaultvalue':def['cmi.learner_preference.delivery_speed'], 'format':CMIDecimal, 'range':speed_range, 'mod':'rw'},
+        'cmi.learner_preference.audio_captioning':{'defaultvalue':def['cmi.learner_preference.audio_captioning'], 'format':CMISInteger, 'range':text_range, 'mod':'rw'},
+        'cmi.location':{'defaultvalue':def['cmi.location'], 'format':CMIString1000, 'mod':'rw'},
+        'cmi.max_time_allowed':{'defaultvalue':def['cmi.max_time_allowed'], 'mod':'r'},
+        'cmi.mode':{'defaultvalue':def['cmi.mode'], 'mod':'r'},
         'cmi.objectives._children':{'defaultvalue':objectives_children, 'mod':'r'},
         'cmi.objectives._count':{'mod':'r', 'defaultvalue':'0'},
         'cmi.objectives.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'},
@@ -219,18 +205,18 @@ function SCORMapi1_3() {
         'cmi.objectives.n.completion_status':{'defaultvalue':'unknown', 'pattern':CMIIndex, 'format':CMICStatus, 'mod':'rw'},
         'cmi.objectives.n.progress_measure':{'defaultvalue':null, 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'},
         'cmi.objectives.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'},
-        'cmi.progress_measure':{'defaultvalue':<?php echo !empty($userdata->{'cmi.progress_measure'})?'\''.$userdata->{'cmi.progress_measure'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'},
-        'cmi.scaled_passing_score':{'defaultvalue':<?php echo !empty($userdata->{'cmi.scaled_passing_score'})?'\''.$userdata->{'cmi.scaled_passing_score'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':scaled_range, 'mod':'r'},
+        'cmi.progress_measure':{'defaultvalue':def['cmi.progress_measure'], 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'},
+        'cmi.scaled_passing_score':{'defaultvalue':def['cmi.scaled_passing_score'], 'format':CMIDecimal, 'range':scaled_range, 'mod':'r'},
         'cmi.score._children':{'defaultvalue':score_children, 'mod':'r'},
-        'cmi.score.scaled':{'defaultvalue':<?php echo !empty($userdata->{'cmi.score.scaled'})?'\''.$userdata->{'cmi.score.scaled'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':scaled_range, 'mod':'rw'},
-        'cmi.score.raw':{'defaultvalue':<?php echo !empty($userdata->{'cmi.score.raw'})?'\''.$userdata->{'cmi.score.raw'}.'\'':'null' ?>, 'format':CMIDecimal, 'mod':'rw'},
-        'cmi.score.min':{'defaultvalue':<?php echo !empty($userdata->{'cmi.score.min'})?'\''.$userdata->{'cmi.score.min'}.'\'':'null' ?>, 'format':CMIDecimal, 'mod':'rw'},
-        'cmi.score.max':{'defaultvalue':<?php echo !empty($userdata->{'cmi.score.max'})?'\''.$userdata->{'cmi.score.max'}.'\'':'null' ?>, 'format':CMIDecimal, 'mod':'rw'},
+        'cmi.score.scaled':{'defaultvalue':def['cmi.score.scaled'], 'format':CMIDecimal, 'range':scaled_range, 'mod':'rw'},
+        'cmi.score.raw':{'defaultvalue':def['cmi.score.raw'], 'format':CMIDecimal, 'mod':'rw'},
+        'cmi.score.min':{'defaultvalue':def['cmi.score.min'], 'format':CMIDecimal, 'mod':'rw'},
+        'cmi.score.max':{'defaultvalue':def['cmi.score.max'], 'format':CMIDecimal, 'mod':'rw'},
         'cmi.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'PT0H0M0S'},
-        'cmi.success_status':{'defaultvalue':'<?php echo !empty($userdata->{'cmi.success_status'})?$userdata->{'cmi.success_status'}:'unknown' ?>', 'format':CMISStatus, 'mod':'rw'},
-        'cmi.suspend_data':{'defaultvalue':<?php echo !empty($userdata->{'cmi.suspend_data'})?'\''.$userdata->{'cmi.suspend_data'}.'\'':'null' ?>, 'format':CMIString64000, 'mod':'rw'},
-        'cmi.time_limit_action':{'defaultvalue':<?php echo !empty($userdata->timelimitaction)?'\''.$userdata->timelimitaction.'\'':'null' ?>, 'mod':'r'},
-        'cmi.total_time':{'defaultvalue':'<?php echo !empty($userdata->{'cmi.total_time'})?$userdata->{'cmi.total_time'}:'PT0H0M0S' ?>', 'mod':'r'},
+        'cmi.success_status':{'defaultvalue':def['cmi.success_status'], 'format':CMISStatus, 'mod':'rw'},
+        'cmi.suspend_data':{'defaultvalue':def['cmi.suspend_data'], 'format':CMIString64000, 'mod':'rw'},
+        'cmi.time_limit_action':{'defaultvalue':def['cmi.time_limit_action'], 'mod':'r'},
+        'cmi.total_time':{'defaultvalue':def['cmi.total_time'], 'mod':'r'},
         'adl.nav.request':{'defaultvalue':'_none_', 'format':NAVEvent, 'mod':'rw'}
     };
     //
@@ -263,13 +249,10 @@ function SCORMapi1_3() {
         }
     }
 
-<?php
-    // reconstitute objectives, comments_from_learner and comments_from_lms
-    scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.objectives', array('score'));
-    scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.interactions', array('objectives', 'correct_responses'));
-    scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.comments_from_learner', array());
-    scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.comments_from_lms', array());
-?>
+    eval(cmiobj);
+    eval(cmiint);
+    eval(cmicommentsuser);
+    eval(cmicommentslms);
 
     if (cmi.completion_status == '') {
         cmi.completion_status = 'not attempted';
@@ -289,11 +272,9 @@ function SCORMapi1_3() {
             if ((!Initialized) && (!Terminated)) {
                 Initialized = true;
                 errorCode = "0";
-                <?php
-                    if (scorm_debugging($scorm)) {
-                        echo 'LogAPICall("Initialize", param, "", errorCode);';
-                    }
-                ?>
+                if (scormdebugging) {
+                    LogAPICall("Initialize", param, "", errorCode);
+                }
                 return "true";
             } else {
                 if (Initialized) {
@@ -305,11 +286,9 @@ function SCORMapi1_3() {
         } else {
             errorCode = "201";
         }
-        <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("Initialize", param, "", errorCode);';
-            }
-        ?>
+        if (scormdebugging) {
+            LogAPICall("Initialize", param, "", errorCode);
+        }
         return "false";
     }
 
@@ -318,18 +297,14 @@ function SCORMapi1_3() {
         if (param == "") {
             if ((Initialized) && (!Terminated)) {
                 var AJAXResult = StoreData(cmi,true);
-                <?php
-                    if (scorm_debugging($scorm)) {
-                        echo 'LogAPICall("Terminate", "AJAXResult", AJAXResult, 0);';
-                    }
-                ?>
+                if (scormdebugging) {
+                    LogAPICall("Terminate", "AJAXResult", AJAXResult, 0);
+                }
                 result = ('true' == AJAXResult) ? 'true' : 'false';
                 errorCode = ('true' == result)? '0' : '101'; // General exception for any AJAX fault
-                <?php
-                    if (scorm_debugging($scorm)) {
-                        echo 'LogAPICall("Terminate", "result", result, errorCode);';
-                    }
-                ?>
+                if (scormdebugging) {
+                    LogAPICall("Terminate", "result", result, errorCode);
+                }
                 if ('true' == result) {
                     Initialized = false;
                     Terminated = true;
@@ -353,16 +328,15 @@ function SCORMapi1_3() {
                             break;
                         }
                     } else {
-                        if (<?php echo $scorm->auto ?> == 1) {
+                        if (scormauto == 1) {
                             setTimeout('mod_scorm_launch_next_sco();',500);
                         }
                     }
                     // trigger TOC update
-                    var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
                     var callback = M.mod_scorm.connectPrereqCallback;
                     YUI().use('io-base', function(Y) {
                         Y.on('io:complete', callback.success, Y);
-                        Y.io(sURL);
+                        Y.io(prerequrl);
                     });
                 } else {
                     diagnostic = "Failure calling the Terminate remote callback: the server replied with HTTP Status " + AJAXResult;
@@ -378,11 +352,9 @@ function SCORMapi1_3() {
         } else {
             errorCode = "201";
         }
-        <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("Terminate", param, "", errorCode);';
-            }
-        ?>
+        if (scormdebugging) {
+            LogAPICall("Terminate", param, "", errorCode);
+        }
         return "false";
     }
 
@@ -410,11 +382,9 @@ function SCORMapi1_3() {
 
                             if ((typeof eval(subelement) != "undefined") && (eval(subelement) != null)) {
                                 errorCode = "0";
-                                <?php
-                                    if (scorm_debugging($scorm)) {
-                                        echo 'LogAPICall("GetValue", element, eval(element), 0);';
-                                    }
-                                ?>
+                                if (scormdebugging) {
+                                    LogAPICall("GetValue", element, eval(element), 0);
+                                }
                                 return eval(element);
                             } else {
                                 errorCode = "403";
@@ -475,11 +445,9 @@ function SCORMapi1_3() {
                 errorCode = "122";
             }
         }
-        <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("GetValue", element, "", errorCode);';
-            }
-        ?>
+        if (scormdebugging) {
+            LogAPICall("GetValue", element, "", errorCode);
+        }
         return "";
     }
 
@@ -724,7 +692,7 @@ function SCORMapi1_3() {
                                                 }
                                              break;
                                          case 'cmi.interactions.n.correct_responses.n.pattern':
-                                                subel= subelement.split('.');
+                                           subel= subelement.split('.');
                                              subel1= 'cmi.interactions.'+subel[2];
 
                                                 if (typeof eval(subel1+'.type') == "undefined") {
@@ -771,11 +739,9 @@ function SCORMapi1_3() {
                                         if ((ranges[1] == '*') || (value <= ranges[1])) {
                                             eval(element+'=value;');
                                             errorCode = "0";
-                                            <?php
-                                                if (scorm_debugging($scorm)) {
-                                                    echo 'LogAPICall("SetValue", element, value, errorCode);';
-                                                }
-                                            ?>
+                                            if (scormdebugging) {
+                                                LogAPICall("SetValue", element, value, errorCode);
+                                            }
                                             return "true";
                                         } else {
                                             errorCode = '407';
@@ -786,11 +752,9 @@ function SCORMapi1_3() {
                                 } else {
                                     eval(element+'=value;');
                                     errorCode = "0";
-                                    <?php
-                                        if (scorm_debugging($scorm)) {
-                                            echo 'LogAPICall("SetValue", element, value, errorCode);';
-                                        }
-                                    ?>
+                                    if (scormdebugging) {
+                                        LogAPICall("SetValue", element, value, errorCode);
+                                    }
                                     return "true";
                                 }
                             }
@@ -813,11 +777,9 @@ function SCORMapi1_3() {
                 errorCode = "132";
             }
         }
-        <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("SetValue", element, value, errorCode);';
-            }
-        ?>
+        if (scormdebugging) {
+            LogAPICall("SetValue", element, value, errorCode);
+        }
         return "false";
     }
 
@@ -940,18 +902,14 @@ function SCORMapi1_3() {
         if (param == "") {
             if ((Initialized) && (!Terminated)) {
                 var AJAXResult = StoreData(cmi,false);
-                <?php
-                    if (scorm_debugging($scorm)) {
-                        echo 'LogAPICall("Commit", "AJAXResult", AJAXResult, 0);';
-                    }
-                ?>
+                if (scormdebugging) {
+                    LogAPICall("Commit", "AJAXResult", AJAXResult, 0);
+                }
                 var result = ('true' == AJAXResult) ? 'true' : 'false';
                 errorCode = ('true' == result)? '0' : '101'; // General exception for any AJAX fault
-                <?php
-                    if (scorm_debugging($scorm)) {
-                        echo 'LogAPICall("Commit", "result", result, errorCode);';
-                    }
-                ?>
+                if (scormdebugging) {
+                    LogAPICall("Commit", "result", result, errorCode);
+                }
                 if ('false' == result) {
                     diagnostic = "Failure calling the Commit remote callback: the server replied with HTTP Status " + AJAXResult;
                 }
@@ -966,20 +924,16 @@ function SCORMapi1_3() {
         } else {
             errorCode = "201";
         }
-        <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("Commit", param, "", errorCode);';
-            }
-        ?>
+        if (scormdebugging) {
+            LogAPICall("Commit", param, "", errorCode);
+        }
         return "false";
     }
 
     function GetLastError () {
-    <?php
-        if (scorm_debugging($scorm)) {
-            echo 'LogAPICall("GetLastError", "", "", errorCode);';
+        if (scormdebugging) {
+            LogAPICall("GetLastError", "", "", errorCode);
         }
-    ?>
         return errorCode;
     }
 
@@ -1066,36 +1020,28 @@ function SCORMapi1_3() {
                     errorString = "Data Model Dependency Not Established";
                 break;
             }
-            <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("GetErrorString", param,  errorString, 0);';
+            if (scormdebugging) {
+                LogAPICall("GetErrorString", param,  errorString, 0);
             }
-             ?>
             return errorString;
         } else {
-           <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("GetErrorString", param,  "No error string found!", 0);';
+            if (scormdebugging) {
+                LogAPICall("GetErrorString", param,  "No error string found!", 0);
             }
-             ?>
             return "";
         }
     }
 
     function GetDiagnostic (param) {
         if (diagnostic != "") {
-            <?php
-                if (scorm_debugging($scorm)) {
-                    echo 'LogAPICall("GetDiagnostic", param, diagnostic, 0);';
-                }
-            ?>
+            if (scormdebugging) {
+                LogAPICall("GetDiagnostic", param, diagnostic, 0);
+            }
             return diagnostic;
         }
-        <?php
-            if (scorm_debugging($scorm)) {
-                echo 'LogAPICall("GetDiagnostic", param, param, 0);';
-            }
-        ?>
+        if (scormdebugging) {
+            LogAPICall("GetDiagnostic", param, param, 0);
+        }
         return param;
     }
 
@@ -1135,11 +1081,6 @@ function SCORMapi1_3() {
     }
 
     function AddTime (first, second) {
-        <?php
-//            if (scorm_debugging($scorm)) {
-//                echo 'alert("AddTime: "+first+" + "+second);';
-//            }
-        ?>
         var timestring = 'P';
         var matchexpr = /^P((\d+)Y)?((\d+)M)?((\d+)D)?(T((\d+)H)?((\d+)M)?((\d+(\.\d{1,2})?)S)?)?$/;
         var firstarray = first.match(matchexpr);
@@ -1264,10 +1205,10 @@ function SCORMapi1_3() {
         var element = 'adl.nav.request';
         var navrequest = eval(element) != datamodel[element].defaultvalue ? '&'+underscore(element)+'='+encodeURIComponent(eval(element)) : '';
         datastring += navrequest;
-        datastring += '&attempt=<?php echo $attempt ?>';
-        datastring += '&scoid=<?php echo $scoid ?>';
+
         var myRequest = NewHttpReq();
-        var result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/datamodel.php","id=<?php p($id) ?>&a=<?php p($a) ?>&sesskey=<?php echo sesskey() ?>"+datastring);
+        result = DoRequest(myRequest,datamodelurl,datamodelurlparams+datastring);
+
         var results = String(result).split('\n');
         if ((results.length > 2) && (navrequest != '')) {
             eval(results[2]);
@@ -1287,11 +1228,8 @@ function SCORMapi1_3() {
     this.version = '1.0';
 }
 
-var API_1484_11 = new SCORMapi1_3();
+M.scorm_api = {};
 
-<?php
-// pull in the debugging utilities
-if (scorm_debugging($scorm)) {
-    include_once($CFG->dirroot.'/mod/scorm/datamodels/debug.js.php');
-    echo 'AppendToLog("Moodle SCORM 1.3 API Loaded, Activity: '.$scorm->name.', SCO: '.$sco->identifier.'", 0);';
+M.scorm_api.init = function(Y, def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scormdebugging, scormauto, scormid, cfgwwwroot, sesskey, scoid, attempt, viewmode, cmid, currentorg) {
+    window.API_1484_11 = new SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scormdebugging, scormauto, scormid, cfgwwwroot, sesskey, scoid, attempt, viewmode, cmid, currentorg);
 }
diff --git a/mod/scorm/datamodels/scorm_13.php b/mod/scorm/datamodels/scorm_13.php
new file mode 100644 (file)
index 0000000..e8a4f6d
--- /dev/null
@@ -0,0 +1,41 @@
+<?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/>.
+
+require_once($CFG->dirroot.'/mod/scorm/locallib.php');
+
+$userdata = new stdClass();
+$def = get_scorm_default($userdata, $scorm, $scoid, $attempt, $mode);
+
+if (!isset($currentorg)) {
+    $currentorg = '';
+}
+
+// reconstitute objectives, comments_from_learner and comments_from_lms
+$cmiobj = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.objectives', array('score'));
+$cmiint = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.interactions', array('objectives', 'correct_responses'));
+$cmicommentsuser = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.comments_from_learner', array());
+$cmicommentslms = scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.comments_from_lms', array());
+
+$PAGE->requires->js_init_call('M.scorm_api.init', array($def, $cmiobj, $cmiint, $cmicommentsuser, $cmicommentslms,
+                                                        scorm_debugging($scorm), $scorm->auto, $scorm->id, $CFG->wwwroot,
+                                                        sesskey(), $scoid, $attempt, $mode, $id, $currentorg));
+
+
+// pull in the debugging utilities
+if (scorm_debugging($scorm)) {
+    require_once($CFG->dirroot.'/mod/scorm/datamodels/debug.js.php');
+    echo html_writer::script('AppendToLog("Moodle SCORM 1.3 API Loaded, Activity: '.$scorm->name.', SCO: '.$sco->identifier.'", 0);');
+}
index eca069f..2279966 100644 (file)
@@ -1180,3 +1180,108 @@ function scorm_seq_flow ($activity, $direction, $seq, $childrenflag, $userid) {
         return $seq;
     }
 }
+
+/**
+ * Sets up $userdata array and default values for SCORM 1.3 .
+ *
+ * @param stdClass $userdata an empty stdClass variable that should be set up with user values
+ * @param object $scorm package record
+ * @param string $scoid SCO Id
+ * @param string $attempt attempt number for the user
+ * @param string $mode scorm display mode type
+ * @return array The default values that should be used for SCORM 1.3 package
+ */
+function get_scorm_default (&$userdata, $scorm, $scoid, $attempt, $mode) {
+    global $DB, $USER;
+
+    $userdata->student_id = $USER->username;
+    $userdata->student_name = $USER->lastname .', '. $USER->firstname;
+
+    if ($usertrack = scorm_get_tracks($scoid, $USER->id, $attempt)) {
+        // According to SCORM 2004(RTE V1, 4.2.8), only cmi.exit==suspend should allow previous datamodel elements on re-launch.
+        if (isset($usertrack->{'cmi.exit'}) && ($usertrack->{'cmi.exit'} == 'suspend')) {
+            foreach ($usertrack as $key => $value) {
+                $userdata->$key = $value;
+            }
+        } else {
+            $userdata->status = '';
+            $userdata->score_raw = '';
+        }
+    } else {
+        $userdata->status = '';
+        $userdata->score_raw = '';
+    }
+
+    if ($scodatas = scorm_get_sco($scoid, SCO_DATA)) {
+        foreach ($scodatas as $key => $value) {
+            $userdata->$key = $value;
+        }
+    } else {
+        print_error('cannotfindsco', 'scorm');
+    }
+    if (!$sco = scorm_get_sco($scoid)) {
+        print_error('cannotfindsco', 'scorm');
+    }
+
+    if (isset($userdata->status)) {
+        if (!isset($userdata->{'cmi.exit'}) || $userdata->{'cmi.exit'} == 'time-out' || $userdata->{'cmi.exit'} == 'normal') {
+                $userdata->entry = 'ab-initio';
+        } else {
+            if (isset($userdata->{'cmi.exit'}) && ($userdata->{'cmi.exit'} == 'suspend' || $userdata->{'cmi.exit'} ==&nb