Merge branch 'install_master' of git://github.com/amosbot/moodle
authorDan Poltawski <dan@moodle.com>
Thu, 19 Jul 2012 05:41:50 +0000 (13:41 +0800)
committerDan Poltawski <dan@moodle.com>
Thu, 19 Jul 2012 05:41:50 +0000 (13:41 +0800)
78 files changed:
admin/cli/mysql_collation.php [new file with mode: 0644]
admin/roles/check.php
admin/settings/grades.php
auth/shibboleth/login.php
backup/moodle2/backup_stepslib.php
backup/moodle2/restore_stepslib.php
blocks/blog_recent/block_blog_recent.php
blocks/completionstatus/block_completionstatus.php
blog/index.php
calendar/lib.php
course/completion_form.php
course/delete.php
course/dndupload.js
course/editsection.php
course/externallib.php
course/format/renderer.php
course/lib.php
enrol/authorize/index.php
enrol/database/tests/adodb_test.php
filter/tex/latex.php
filter/tex/texdebug.php
grade/export/lib.php
grade/export/ods/export.php
grade/export/ods/grade_export_ods.php
grade/export/ods/index.php
grade/export/txt/export.php
grade/export/txt/grade_export_txt.php
grade/export/txt/index.php
grade/export/xls/export.php
grade/export/xls/grade_export_xls.php
grade/export/xls/index.php
grade/lib.php
lang/en/completion.php
lang/en/error.php
lang/en/grades.php
lang/en/notes.php
lang/en/role.php
lib/accesslib.php
lib/completion/completion_criteria_course.php
lib/completion/cron.php
lib/db/install.xml
lib/db/services.php
lib/ddl/mysql_sql_generator.php
lib/dml/mysqli_native_moodle_database.php
lib/form/yui/dateselector/assets/skins/sam/dateselector.css
lib/form/yui/dateselector/dateselector.js
lib/formslib.php
lib/javascript-static.js
lib/navigationlib.php
lib/yui/formchangechecker/formchangechecker.js
mod/assign/lang/en/assign.php
mod/assign/locallib.php
mod/assign/settings.php
mod/assignment/lib.php
mod/assignment/type/online/assignment.class.php
mod/chat/gui_ajax/module.js
mod/choice/renderer.php
mod/data/export.php
mod/forum/lib.php
mod/forum/mod_form.php
mod/forum/post.php
mod/quiz/module.js
mod/quiz/renderer.php
mod/quiz/report/overview/report.php
mod/quiz/report/statistics/report.php
mod/quiz/version.php
notes/externallib.php
plagiarism/lib.php
portfolio/googledocs/lib.php
portfolio/picasa/lib.php
question/type/shortanswer/backup/moodle2/restore_qtype_shortanswer_plugin.class.php
repository/filepicker.js
repository/googledocs/lib.php
repository/picasa/lib.php
theme/base/style/course.css
theme/base/style/filemanager.css
user/lib.php
version.php

diff --git a/admin/cli/mysql_collation.php b/admin/cli/mysql_collation.php
new file mode 100644 (file)
index 0000000..9938a3a
--- /dev/null
@@ -0,0 +1,211 @@
+<?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/>.
+
+/**
+ * MySQL collation conversion tool.
+ *
+ * @package    core
+ * @copyright  2012 Petr Skoda (http://skodak.org)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('CLI_SCRIPT', true);
+
+require(dirname(dirname(dirname(__FILE__))).'/config.php');
+require_once($CFG->libdir.'/clilib.php');      // cli only functions
+
+if ($DB->get_dbfamily() !== 'mysql') {
+    cli_error('This function is designed for MySQL databases only!');
+}
+
+// now get cli options
+list($options, $unrecognized) = cli_get_params(array('help'=>false, 'list'=>false, 'collation'=>false, 'available'=>false),
+    array('h'=>'help', 'l'=>'list', 'a'=>'available'));
+
+if ($unrecognized) {
+    $unrecognized = implode("\n  ", $unrecognized);
+    cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
+}
+
+$help =
+    "MySQL collation conversions script.
+
+It is strongly recommended to stop the web server before the conversion.
+This script may be executed before the main upgrade - 1.9.x data for example.
+
+Options:
+--collation=COLLATION Convert MySQL tables to different collation
+-l, --list            Show table and column information
+-a, --available       Show list of available collations
+-h, --help            Print out this help
+
+Example:
+\$ sudo -u www-data /usr/bin/php admin/cli/mysql_collation.php --collation=utf8_general_ci
+";
+
+if (!empty($options['collation'])) {
+    $collations = mysql_get_collations();
+    $collation = clean_param($options['collation'], PARAM_ALPHANUMEXT);
+    $collation = strtolower($collation);
+    if (!isset($collations[$collation])) {
+        cli_error("Error: collation '$collation' is not available on this server!");
+    }
+
+    echo "Converting tables and columns to '$collation' for $CFG->wwwroot:\n";
+    $prefix = $DB->get_prefix();
+    $prefix = str_replace('_', '\\_', $prefix);
+    $sql = "SHOW TABLE STATUS WHERE Name LIKE BINARY '$prefix%'";
+    $rs = $DB->get_recordset_sql($sql);
+    $converted = 0;
+    $skipped   = 0;
+    $errors    = 0;
+    foreach ($rs as $table) {
+        echo str_pad($table->name, 40). " - ";
+
+        if ($table->collation === $collation) {
+            echo "NO CHANGE\n";
+            $skipped++;
+
+        } else {
+            $DB->change_database_structure("ALTER TABLE $table->name DEFAULT COLLATE = $collation");
+            echo "CONVERTED\n";
+            $converted++;
+        }
+
+        $sql = "SHOW FULL COLUMNS FROM $table->name WHERE collation IS NOT NULL";
+        $rs2 = $DB->get_recordset_sql($sql);
+        foreach ($rs2 as $column) {
+            $column = (object)array_change_key_case((array)$column, CASE_LOWER);
+            echo '    '.str_pad($column->field, 36). " - ";
+            if ($column->collation === $collation) {
+                echo "NO CHANGE\n";
+                $skipped++;
+                continue;
+            }
+
+            if ($column->type === 'tinytext' or $column->type === 'mediumtext' or $column->type === 'text' or $column->type === 'longtext') {
+                $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
+                $default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : '';
+                // primary, unique and inc are not supported for texts
+                $sql = "ALTER TABLE $table->name MODIFY COLUMN $column->field $column->type COLLATE $collation $notnull $default";
+                $DB->change_database_structure($sql);
+
+            } else if (strpos($column->type, 'varchar') === 0) {
+                $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
+                $default = !is_null($column->default) ? "DEFAULT '$column->default'" : '';
+                // primary, unique and inc are not supported for texts
+                $sql = "ALTER TABLE $table->name MODIFY COLUMN $column->field $column->type COLLATE $collation $notnull $default";
+                $DB->change_database_structure($sql);
+            } else {
+                echo "ERROR (unknown column type: $column->type)\n";
+                $error++;
+                continue;
+            }
+            echo "CONVERTED\n";
+            $converted++;
+        }
+        $rs2->close();
+    }
+    $rs->close();
+    echo "Converted: $converted, skipped: $skipped, errors: $errors\n";
+    exit(0); // success
+
+} else if (!empty($options['list'])) {
+    echo "List of tables for $CFG->wwwroot:\n";
+    $prefix = $DB->get_prefix();
+    $prefix = str_replace('_', '\\_', $prefix);
+    $sql = "SHOW TABLE STATUS WHERE Name LIKE BINARY '$prefix%'";
+    $rs = $DB->get_recordset_sql($sql);
+    $counts = array();
+    foreach ($rs as $table) {
+        if (isset($counts[$table->collation])) {
+            $counts[$table->collation]++;
+        } else {
+            $counts[$table->collation] = 1;
+        }
+        echo str_pad($table->name, 40);
+        echo $table->collation.  "\n";
+        $collations = mysql_get_column_collations($table->name);
+        foreach ($collations as $columname=>$collation) {
+            if (isset($counts[$collation])) {
+                $counts[$collation]++;
+            } else {
+                $counts[$collation] = 1;
+            }
+            echo '    ';
+            echo str_pad($columname, 36);
+            echo $collation.  "\n";
+        }
+    }
+    $rs->close();
+
+    echo "\n";
+    echo "Table collations summary for $CFG->wwwroot:\n";
+    foreach ($counts as $collation => $count) {
+        echo "$collation: $count\n";
+    }
+    exit(0); // success
+
+} else if (!empty($options['available'])) {
+    echo "List of available MySQL collations for $CFG->wwwroot:\n";
+    $collations = mysql_get_collations();
+    foreach ($collations as $collation) {
+        echo " $collation\n";
+    }
+    die;
+
+} else {
+    echo $help;
+    die;
+}
+
+
+
+// ========== Some functions ==============
+
+function mysql_get_collations() {
+    global $DB;
+
+    $collations = array();
+    $sql = "SHOW COLLATION WHERE Collation LIKE 'utf8\_%' AND Charset = 'utf8'";
+    $rs = $DB->get_recordset_sql($sql);
+    foreach ($rs as $collation) {
+        $collations[$collation->collation] = $collation->collation;
+    }
+    $rs->close();
+
+    $collation = $DB->get_dbcollation();
+    if (isset($collations[$collation])) {
+        $collations[$collation] .= ' (default)';
+    }
+
+    return $collations;
+}
+
+function mysql_get_column_collations($tablename) {
+    global $DB;
+
+    $collations = array();
+    $sql = "SELECT column_name, collation_name
+              FROM INFORMATION_SCHEMA.COLUMNS
+             WHERE table_schema = DATABASE() AND table_name = ? AND collation_name IS NOT NULL";
+    $rs = $DB->get_recordset_sql($sql, array($tablename));
+    foreach($rs as $record) {
+        $collations[$record->column_name] = $record->collation_name;
+    }
+    $rs->close();
+    return $collations;
+}
index 1f6f6ac..470159e 100644 (file)
@@ -104,20 +104,45 @@ switch ($context->contextlevel) {
         break;
 }
 
+// Get the list of the reported-on user's role assignments - must be after
+// the page setup code above, or the language might be wrong.
+$reportuser = $userselector->get_selected_user();
+if (!is_null($reportuser)) {
+    $roleassignments = get_user_roles_with_special($context, $reportuser->id);
+    $rolenames = role_get_names($context);
+}
+
 echo $OUTPUT->header();
-// These are needed early because of tabs.php
-$assignableroles = get_assignable_roles($context, ROLENAME_BOTH);
-$overridableroles = get_overridable_roles($context, ROLENAME_BOTH);
 
 // Print heading.
 echo $OUTPUT->heading($title);
 
 // If a user has been chosen, show all the permissions for this user.
-$reportuser = $userselector->get_selected_user();
 if (!is_null($reportuser)) {
     echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthwide');
-    echo $OUTPUT->heading(get_string('permissionsforuser', 'role', fullname($reportuser)), 3);
 
+    if (!empty($roleassignments)) {
+        echo $OUTPUT->heading(get_string('rolesforuser', 'role', fullname($reportuser)), 3);
+        echo html_writer::start_tag('ul');
+
+        $systemcontext = context_system::instance();
+        foreach ($roleassignments as $ra) {
+            $racontext = context::instance_by_id($ra->contextid);
+            $link = html_writer::link($racontext->get_url(), $racontext->get_context_name());
+
+            $rolename = $rolenames[$ra->roleid]->localname;
+            if (has_capability('moodle/role:manage', $systemcontext)) {
+                $rolename = html_writer::link(new moodle_url('/admin/roles/define.php',
+                        array('action' => 'view', 'roleid' => $ra->roleid)), $rolename);
+            }
+
+            echo html_writer::tag('li', get_string('roleincontext', 'role',
+                    array('role' => $rolename, 'context' => $link)));
+        }
+        echo html_writer::end_tag('ul');
+    }
+
+    echo $OUTPUT->heading(get_string('permissionsforuser', 'role', fullname($reportuser)), 3);
     $table = new check_capability_table($context, $reportuser, $contextname);
     $table->display();
     echo $OUTPUT->box_end();
index 9915909..53c9ee3 100644 (file)
@@ -58,6 +58,10 @@ if (has_capability('moodle/grade:manage', $systemcontext)
                                                         GRADE_NAVMETHOD_TABS => new lang_string('tabs', 'grades'),
                                                         GRADE_NAVMETHOD_COMBO => new lang_string('combo', 'grades'))));
 
+        $temp->add(new admin_setting_configtext('grade_export_userprofilefields', new lang_string('gradeexportuserprofilefields', 'grades'), new lang_string('gradeexportuserprofilefields_desc', 'grades'), 'firstname,lastname,idnumber,institution,department,email', PARAM_TEXT));
+
+        $temp->add(new admin_setting_configtext('grade_export_customprofilefields', new lang_string('gradeexportcustomprofilefields', 'grades'), new lang_string('gradeexportcustomprofilefields_desc', 'grades'), null, PARAM_TEXT));
+
         $temp->add(new admin_setting_configcheckbox('recovergradesdefault', new lang_string('recovergradesdefault', 'grades'), new lang_string('recovergradesdefault_help', 'grades'), 0));
 
         $temp->add(new admin_setting_special_gradeexport());
index ee3372f..6f984c5 100644 (file)
@@ -63,6 +63,7 @@ $PAGE->https_required();
     $loginsite = get_string("loginsite");
 
     $PAGE->set_url('/auth/shibboleth/login.php');
+    $PAGE->set_context(context_system::instance());
     $PAGE->navbar->add($loginsite);
     $PAGE->set_title("$site->fullname: $loginsite");
     $PAGE->set_heading($site->fullname);
index a9ef111..a73cafa 100644 (file)
@@ -323,7 +323,7 @@ class backup_module_structure_step extends backup_structure_step {
         $availability = new backup_nested_element('availability', array('id'), array(
             'sourcecmid', 'requiredcompletion', 'gradeitemid', 'grademin', 'grademax'));
         $availabilityfield = new backup_nested_element('availability_field', array('id'), array(
-            'userfield', 'customfieldid', 'operator', 'value'));
+            'userfield', 'customfield', 'customfieldtype', 'operator', 'value'));
 
         // attach format plugin structure to $module element, only one allowed
         $this->add_plugin_structure('format', $module, false);
@@ -346,7 +346,11 @@ class backup_module_structure_step extends backup_structure_step {
              WHERE cm.id = ?', array(backup::VAR_MODID));
 
         $availability->set_source_table('course_modules_availability', array('coursemoduleid' => backup::VAR_MODID));
-        $availabilityfield->set_source_table('course_modules_avail_fields', array('coursemoduleid' => backup::VAR_MODID));
+        $availabilityfield->set_source_sql('
+            SELECT cmaf.*, uif.shortname AS customfield, uif.datatype AS customfieldtype
+              FROM {course_modules_avail_fields} cmaf
+         LEFT JOIN {user_info_field} uif ON uif.id = cmaf.customfieldid
+             WHERE cmaf.coursemoduleid = ?', array(backup::VAR_MODID));
 
         // Define annotations
         $module->annotate_ids('grouping', 'groupingid');
@@ -377,14 +381,18 @@ class backup_section_structure_step extends backup_structure_step {
         $avail = new backup_nested_element('availability', array('id'), array(
                 'sourcecmid', 'requiredcompletion', 'gradeitemid', 'grademin', 'grademax'));
         $availfield = new backup_nested_element('availability_field', array('id'), array(
-            'userfield', 'customfieldid', 'operator', 'value'));
+            'userfield', 'operator', 'value', 'customfield', 'customfieldtype'));
         $section->add_child($avail);
         $section->add_child($availfield);
 
         // Define sources
         $section->set_source_table('course_sections', array('id' => backup::VAR_SECTIONID));
         $avail->set_source_table('course_sections_availability', array('coursesectionid' => backup::VAR_SECTIONID));
-        $availfield->set_source_table('course_sections_avail_fields', array('coursesectionid' => backup::VAR_SECTIONID));
+        $availfield->set_source_sql('
+            SELECT csaf.*, uif.shortname AS customfield, uif.datatype AS customfieldtype
+              FROM {course_sections_avail_fields} csaf
+         LEFT JOIN {user_info_field} uif ON uif.id = csaf.customfieldid
+             WHERE csaf.coursesectionid = ?', array(backup::VAR_SECTIONID));
 
         // Aliases
         $section->set_source_alias('section', 'number');
index 6bed961..1bd5a48 100644 (file)
@@ -1139,18 +1139,26 @@ class restore_section_structure_step extends restore_structure_step {
         $data = (object)$data;
         // Mark it is as passed by default
         $passed = true;
-        // Ok, if it is a profile field we need to check it exists
-        if (!is_null($data->customfieldid)) {
-            if (!$DB->record_exists('user_info_field', array('id' => $data->customfieldid))) {
-                $passed = false;
-            }
+        $customfieldid = null;
+
+        // If a customfield has been used in order to pass we must be able to match an existing
+        // customfield by name (data->customfield) and type (data->customfieldtype)
+        if (is_null($data->customfield) xor is_null($data->customfieldtype)) {
+            // xor is sort of uncommon. If either customfield is null or customfieldtype is null BUT not both.
+            // If one is null but the other isn't something clearly went wrong and we'll skip this condition.
+            $passed = false;
+        } else if (!is_null($data->customfield)) {
+            $params = array('shortname' => $data->customfield, 'datatype' => $data->customfieldtype);
+            $customfieldid = $DB->get_field('user_info_field', 'id', $params);
+            $passed = ($customfieldid !== false);
         }
+
         if ($passed) {
             // Create the object to insert into the database
             $availfield = new stdClass();
             $availfield->coursesectionid = $this->task->get_sectionid();
             $availfield->userfield = $data->userfield;
-            $availfield->customfieldid = $data->customfieldid;
+            $availfield->customfieldid = $customfieldid;
             $availfield->operator = $data->operator;
             $availfield->value = $data->value;
             $DB->insert_record('course_sections_avail_fields', $availfield);
@@ -2637,18 +2645,26 @@ class restore_module_structure_step extends restore_structure_step {
         $data = (object)$data;
         // Mark it is as passed by default
         $passed = true;
-        // Ok, if it is a profile field we need to check it exists
-        if (!is_null($data->customfieldid)) {
-            if (!$DB->record_exists('user_info_field', array('id' => $data->customfieldid))) {
-                $passed = false;
-            }
+        $customfieldid = null;
+
+        // If a customfield has been used in order to pass we must be able to match an existing
+        // customfield by name (data->customfield) and type (data->customfieldtype)
+        if (!empty($data->customfield) xor !empty($data->customfieldtype)) {
+            // xor is sort of uncommon. If either customfield is null or customfieldtype is null BUT not both.
+            // If one is null but the other isn't something clearly went wrong and we'll skip this condition.
+            $passed = false;
+        } else if (!empty($data->customfield)) {
+            $params = array('shortname' => $data->customfield, 'datatype' => $data->customfieldtype);
+            $customfieldid = $DB->get_field('user_info_field', 'id', $params);
+            $passed = ($customfieldid !== false);
         }
+
         if ($passed) {
             // Create the object to insert into the database
             $availfield = new stdClass();
             $availfield->coursemoduleid = $this->task->get_moduleid(); // Lets add the availability cmid
             $availfield->userfield = $data->userfield;
-            $availfield->customfieldid = $data->customfieldid;
+            $availfield->customfieldid = $customfieldid;
             $availfield->operator = $data->operator;
             $availfield->value = $data->value;
             // Insert into the database
index b3d564f..fe6c970 100644 (file)
@@ -86,17 +86,20 @@ class block_blog_recent extends block_base {
 
         $context = $this->page->context;
 
+        $url = new moodle_url('/blog/index.php');
         $filter = array();
         if ($context->contextlevel == CONTEXT_MODULE) {
             $filter['module'] = $context->instanceid;
             $a = new stdClass;
             $a->type = get_string('modulename', $this->page->cm->modname);
             $strview = get_string('viewallmodentries', 'blog', $a);
+            $url->param('modid', $context->instanceid);
         } else if ($context->contextlevel == CONTEXT_COURSE) {
             $filter['course'] = $context->instanceid;
             $a = new stdClass;
             $a->type = get_string('course');
             $strview = get_string('viewblogentries', 'blog', $a);
+            $url->param('courseid', $context->instanceid);
         } else {
             $strview = get_string('viewsiteentries', 'blog');
         }
@@ -104,7 +107,6 @@ class block_blog_recent extends block_base {
 
         $bloglisting = new blog_listing($filter);
         $entries = $bloglisting->get_entries(0, $this->config->numberofrecentblogentries, 4);
-        $url = new moodle_url('/blog/index.php', $filter);
 
         if (!empty($entries)) {
             $entrieslist = array();
index 0daec7c..52cd48d 100644 (file)
@@ -166,7 +166,7 @@ class block_completionstatus extends block_base {
         if (!empty($prerequisites)) {
 
             $phtml  = '<tr><td>';
-            $phtml .= get_string('prerequisitescompleted', 'completion');
+            $phtml .= get_string('dependenciescompleted', 'completion');
             $phtml .= '</td><td style="text-align: right">';
             $a = new stdClass();
             $a->first = $prerequisites_complete;
index 77476a9..c008427 100644 (file)
@@ -143,7 +143,7 @@ if (!empty($groupid)) {
     }
 
     if (!$course = $DB->get_record('course', array('id'=>$group->courseid))) {
-        print_error(get_string('invalidcourseid', 'blog'));
+        print_error('invalidcourseid');
     }
 
     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
index 8152990..6cff2a3 100644 (file)
@@ -85,14 +85,6 @@ define('CALENDAR_EVENT_GROUP', 4);
  */
 define('CALENDAR_EVENT_USER', 8);
 
-/**
- * CALENDAR_STARTING_WEEKDAY - has since been deprecated please call calendar_get_starting_weekday() instead
- *
- * @deprecated Moodle 2.0 MDL-24284- please do not use this function any more.
- * @todo MDL-31132 This will be deleted in Moodle 2.3.
- * @see calendar_get_starting_weekday()
- */
-define('CALENDAR_STARTING_WEEKDAY', CALENDAR_DEFAULT_STARTING_WEEKDAY);
 
 /**
  * Return the days of the week
index 951776a..f13f2af 100644 (file)
@@ -65,7 +65,7 @@ class course_completion_form extends moodleform {
         $mform->setDefault('overall_aggregation', $completion->get_aggregation_method());
 
         // Course prerequisite completion criteria
-        $mform->addElement('header', 'courseprerequisites', get_string('courseprerequisites', 'completion'));
+        $mform->addElement('header', 'courseprerequisites', get_string('completiondependencies', 'completion'));
 
         // Get applicable courses
         $courses = $DB->get_records_sql(
index ba9c3be..ebe6b78 100644 (file)
     $strcategories = get_string("categories");
 
     if (! $course = $DB->get_record("course", array("id"=>$id))) {
-        print_error("invalidcourseid", 'error', '', $id);
+        print_error("invalidcourseid");
     }
     if ($site->id == $course->id) {
         // can not delete frontpage!
-        print_error("invalidcourseid", 'error', '', $id);
+        print_error("invalidcourseid");
     }
 
     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
index 4651120..7bfef1d 100644 (file)
@@ -514,7 +514,7 @@ M.course_dndupload = {
             namespan: document.createElement('span')
         };
 
-        preview.li.className = 'dndupload-preview activity resource modtype_resource dndupload-hidden';
+        preview.li.className = 'dndupload-preview dndupload-hidden';
 
         preview.div.className = 'mod-indent';
         preview.li.appendChild(preview.div);
index d67b179..87ce0d5 100644 (file)
@@ -33,9 +33,9 @@ require_once($CFG->libdir . '/conditionlib.php');
 require_once('editsection_form.php');
 
 $id = required_param('id',PARAM_INT);    // Week/topic ID
-$sectionreturn = optional_param('sectionreturn', 0, PARAM_BOOL);
+$sectionreturn = optional_param('sr', 0, PARAM_INT);
 
-$PAGE->set_url('/course/editsection.php', array('id'=>$id, 'sectionreturn'=> $sectionreturn));
+$PAGE->set_url('/course/editsection.php', array('id'=>$id, 'sr'=> $sectionreturn));
 
 $section = $DB->get_record('course_sections', array('id' => $id), '*', MUST_EXIST);
 $course = $DB->get_record('course', array('id' => $section->course), '*', MUST_EXIST);
@@ -61,11 +61,7 @@ $mform = new editsection_form($PAGE->url, array('course' => $course, 'editoropti
         'cs' => $section, 'showavailability' => $section->showavailability));
 $mform->set_data($section); // set current value
 
-if ($sectionreturn) {
-    $returnurl = course_get_url($course, $section->section);
-} else {
-    $returnurl = course_get_url($course);
-}
+$returnurl = course_get_url($course, $sectionreturn);
 
 /// If data submitted, then process and store.
 if ($mform->is_cancelled()){
index 41c5ab4..cceca17 100644 (file)
@@ -668,13 +668,12 @@ class core_course_external extends external_api {
                 'options' => new external_multiple_structure(
                     new external_single_structure(
                         array(
-                                'name' => new external_value(PARAM_ALPHA, 'The backup option name:
+                                'name' => new external_value(PARAM_ALPHAEXT, 'The backup option name:
                                             "activities" (int) Include course activites (default to 1 that is equal to yes),
                                             "blocks" (int) Include course blocks (default to 1 that is equal to yes),
                                             "filters" (int) Include course filters  (default to 1 that is equal to yes),
                                             "users" (int) Include users (default to 0 that is equal to no),
                                             "role_assignments" (int) Include role assignments  (default to 0 that is equal to no),
-                                            "user_files" (int) Include user files  (default to 0 that is equal to no),
                                             "comments" (int) Include user comments  (default to 0 that is equal to no),
                                             "completion_information" (int) Include user course completion information  (default to 0 that is equal to no),
                                             "logs" (int) Include course logs  (default to 0 that is equal to no),
@@ -722,7 +721,7 @@ class core_course_external extends external_api {
         // Context validation.
 
         if (! ($course = $DB->get_record('course', array('id'=>$params['courseid'])))) {
-            throw new moodle_exception('invalidcourseid', 'error', '', $params['courseid']);
+            throw new moodle_exception('invalidcourseid', 'error');
         }
 
         // Category where duplicated course is going to be created.
@@ -739,7 +738,6 @@ class core_course_external extends external_api {
             'filters' => 1,
             'users' => 0,
             'role_assignments' => 0,
-            'user_files' => 0,
             'comments' => 0,
             'completion_information' => 0,
             'logs' => 0,
@@ -885,6 +883,189 @@ class core_course_external extends external_api {
         );
     }
 
+    /**
+     * Returns description of method parameters for import_course
+     *
+     * @return external_function_parameters
+     * @since Moodle 2.4
+     */
+    public static function import_course_parameters() {
+        return new external_function_parameters(
+            array(
+                'importfrom' => new external_value(PARAM_INT, 'the id of the course we are importing from'),
+                'importto' => new external_value(PARAM_INT, 'the id of the course we are importing to'),
+                'deletecontent' => new external_value(PARAM_INT, 'whether to delete the course content where we are importing to (default to 0 = No)', VALUE_DEFAULT, 0),
+                'options' => new external_multiple_structure(
+                    new external_single_structure(
+                        array(
+                                'name' => new external_value(PARAM_ALPHA, 'The backup option name:
+                                            "activities" (int) Include course activites (default to 1 that is equal to yes),
+                                            "blocks" (int) Include course blocks (default to 1 that is equal to yes),
+                                            "filters" (int) Include course filters  (default to 1 that is equal to yes)'
+                                            ),
+                                'value' => new external_value(PARAM_RAW, 'the value for the option 1 (yes) or 0 (no)'
+                            )
+                        )
+                    ), VALUE_DEFAULT, array()
+                ),
+            )
+        );
+    }
+
+    /**
+     * Imports a course
+     *
+     * @param int $importfrom The id of the course we are importing from
+     * @param int $importto The id of the course we are importing to
+     * @param bool $deletecontent Whether to delete the course we are importing to content
+     * @param array $options List of backup options
+     * @return null
+     * @since Moodle 2.4
+     */
+    public static function import_course($importfrom, $importto, $deletecontent = 0, $options = array()) {
+        global $CFG, $USER, $DB;
+        require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
+        require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
+
+        // Parameter validation.
+        $params = self::validate_parameters(
+            self::import_course_parameters(),
+            array(
+                'importfrom' => $importfrom,
+                'importto' => $importto,
+                'deletecontent' => $deletecontent,
+                'options' => $options
+            )
+        );
+
+        if ($params['deletecontent'] !== 0 and $params['deletecontent'] !== 1) {
+            throw new moodle_exception('invalidextparam', 'webservice', '', $option['deletecontent']);
+        }
+
+        // Context validation.
+
+        if (! ($importfrom = $DB->get_record('course', array('id'=>$params['importfrom'])))) {
+            throw new moodle_exception('invalidcourseid', 'error');
+        }
+
+        if (! ($importto = $DB->get_record('course', array('id'=>$params['importto'])))) {
+            throw new moodle_exception('invalidcourseid', 'error');
+        }
+
+        $importfromcontext = context_course::instance($importfrom->id);
+        self::validate_context($importfromcontext);
+
+        $importtocontext = context_course::instance($importto->id);
+        self::validate_context($importtocontext);
+
+        $backupdefaults = array(
+            'activities' => 1,
+            'blocks' => 1,
+            'filters' => 1
+        );
+
+        $backupsettings = array();
+
+        // Check for backup and restore options.
+        if (!empty($params['options'])) {
+            foreach ($params['options'] as $option) {
+
+                // Strict check for a correct value (allways 1 or 0, true or false).
+                $value = clean_param($option['value'], PARAM_INT);
+
+                if ($value !== 0 and $value !== 1) {
+                    throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
+                }
+
+                if (!isset($backupdefaults[$option['name']])) {
+                    throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
+                }
+
+                $backupsettings[$option['name']] = $value;
+            }
+        }
+
+        // Capability checking.
+
+        require_capability('moodle/backup:backuptargetimport', $importfromcontext);
+        require_capability('moodle/restore:restoretargetimport', $importtocontext);
+
+        $bc = new backup_controller(backup::TYPE_1COURSE, $importfrom->id, backup::FORMAT_MOODLE,
+                backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
+
+        foreach ($backupsettings as $name => $value) {
+            $bc->get_plan()->get_setting($name)->set_value($value);
+        }
+
+        $backupid       = $bc->get_backupid();
+        $backupbasepath = $bc->get_plan()->get_basepath();
+
+        $bc->execute_plan();
+        $bc->destroy();
+
+        // Restore the backup immediately.
+
+        // Check if we must delete the contents of the destination course.
+        if ($params['deletecontent']) {
+            $restoretarget = backup::TARGET_EXISTING_DELETING;
+        } else {
+            $restoretarget = backup::TARGET_EXISTING_ADDING;
+        }
+
+        $rc = new restore_controller($backupid, $importto->id,
+                backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id, $restoretarget);
+
+        foreach ($backupsettings as $name => $value) {
+            $rc->get_plan()->get_setting($name)->set_value($value);
+        }
+
+        if (!$rc->execute_precheck()) {
+            $precheckresults = $rc->get_precheck_results();
+            if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
+                if (empty($CFG->keeptempdirectoriesonbackup)) {
+                    fulldelete($backupbasepath);
+                }
+
+                $errorinfo = '';
+
+                foreach ($precheckresults['errors'] as $error) {
+                    $errorinfo .= $error;
+                }
+
+                if (array_key_exists('warnings', $precheckresults)) {
+                    foreach ($precheckresults['warnings'] as $warning) {
+                        $errorinfo .= $warning;
+                    }
+                }
+
+                throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo);
+            }
+        } else {
+            if ($restoretarget == backup::TARGET_EXISTING_DELETING) {
+                restore_dbops::delete_course_content($importto->id);
+            }
+        }
+
+        $rc->execute_plan();
+        $rc->destroy();
+
+        if (empty($CFG->keeptempdirectoriesonbackup)) {
+            fulldelete($backupbasepath);
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns description of method result value
+     *
+     * @return external_description
+     * @since Moodle 2.4
+     */
+    public static function import_course_returns() {
+        return null;
+    }
+
     /**
      * Returns description of method parameters
      *
index b7c0e21..1309025 100644 (file)
@@ -122,9 +122,10 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
      * @param stdClass $section The course_section entry from DB
      * @param stdClass $course The course entry from DB
      * @param bool $onsectionpage true if being printed on a single-section page
+     * @param int $sectionreturn The section to return to after an action
      * @return string HTML to output.
      */
-    protected function section_header($section, $course, $onsectionpage) {
+    protected function section_header($section, $course, $onsectionpage, $sectionreturn=0) {
         global $PAGE;
 
         $o = '';
@@ -150,7 +151,13 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $o.= html_writer::tag('div', $rightcontent, array('class' => 'right side'));
         $o.= html_writer::start_tag('div', array('class' => 'content'));
 
-        if (!$onsectionpage) {
+        // When not on a section page, we display the section titles except the general section if null
+        $hasnamenotsecpg = (!$onsectionpage && ($section->section != 0 || !is_null($section->name)));
+
+        // When on a section page, we only display the general section title, if title is not the default one
+        $hasnamesecpg = ($onsectionpage && ($section->section == 0 && !is_null($section->name)));
+
+        if ($hasnamenotsecpg || $hasnamesecpg) {
             $o.= $this->output->heading($this->section_title($section, $course), 3, 'sectionname');
         }
 
@@ -159,12 +166,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
 
         $context = context_course::instance($course->id);
         if ($PAGE->user_is_editing() && has_capability('moodle/course:update', $context)) {
-            $url = new moodle_url('/course/editsection.php', array('id'=>$section->id));
-
-            if ($onsectionpage) {
-                $url->param('sectionreturn', 1);
-            }
-
+            $url = new moodle_url('/course/editsection.php', array('id'=>$section->id, 'sr'=>$sectionreturn));
             $o.= html_writer::link($url,
                 html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/edit'), 'class' => 'iconsmall edit')),
                 array('title' => get_string('editsummary')));
@@ -560,10 +562,10 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $thissection = $sections[0];
         if ($thissection->summary or $thissection->sequence or $PAGE->user_is_editing()) {
             echo $this->start_section_list();
-            echo $this->section_header($thissection, $course, true);
-            print_section($course, $thissection, $mods, $modnamesused, true);
+            echo $this->section_header($thissection, $course, true, $displaysection);
+            print_section($course, $thissection, $mods, $modnamesused, true, "100%", false, $displaysection);
             if ($PAGE->user_is_editing()) {
-                print_section_add_menus($course, 0, $modnames, false, false, true);
+                print_section_add_menus($course, 0, $modnames, false, false, $displaysection);
             }
             echo $this->section_footer();
             echo $this->end_section_list();
@@ -592,14 +594,14 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
 
         // The requested section page.
         $thissection = $sections[$displaysection];
-        echo $this->section_header($thissection, $course, true);
+        echo $this->section_header($thissection, $course, true, $displaysection);
         // Show completion help icon.
         $completioninfo = new completion_info($course);
         echo $completioninfo->display_help_icon();
 
-        print_section($course, $thissection, $mods, $modnamesused, true, '100%', false, true);
+        print_section($course, $thissection, $mods, $modnamesused, true, '100%', false, $displaysection);
         if ($PAGE->user_is_editing()) {
-            print_section_add_menus($course, $displaysection, $modnames, false, false, true);
+            print_section_add_menus($course, $displaysection, $modnames, false, false, $displaysection);
         }
         echo $this->section_footer();
         echo $this->end_section_list();
@@ -646,7 +648,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $thissection = $sections[0];
         unset($sections[0]);
         if ($thissection->summary or $thissection->sequence or $PAGE->user_is_editing()) {
-            echo $this->section_header($thissection, $course, true);
+            echo $this->section_header($thissection, $course, false);
             print_section($course, $thissection, $mods, $modnamesused, true);
             if ($PAGE->user_is_editing()) {
                 print_section_add_menus($course, 0, $modnames);
index 5036687..838e194 100644 (file)
@@ -1377,8 +1377,18 @@ function get_print_section_cm_text(cm_info $cm, $course) {
 
 /**
  * Prints a section full of activity modules
+ *
+ * @param stdClass $course The course
+ * @param stdClass $section The section
+ * @param array $mods The modules in the section
+ * @param array $modnamesused An array containing the list of modules and their names
+ * @param bool $absolute All links are absolute
+ * @param string $width Width of the container
+ * @param bool $hidecompletion Hide completion status
+ * @param int $sectionreturn The section to return to
+ * @return void
  */
-function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false, $sectionreturn = false) {
+function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false, $sectionreturn=0) {
     global $CFG, $USER, $DB, $PAGE, $OUTPUT;
 
     static $initialised;
@@ -1638,12 +1648,7 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                     $mod->groupmode = false;
                 }
                 echo '&nbsp;&nbsp;';
-
-                if ($sectionreturn) {
-                    echo make_editing_buttons($mod, $absolute, true, $mod->indent, $section->section);
-                } else {
-                    echo make_editing_buttons($mod, $absolute, true, $mod->indent, 0);
-                }
+                echo make_editing_buttons($mod, $absolute, true, $mod->indent, $sectionreturn);
                 echo $mod->get_after_edit_icons();
             }
 
@@ -1762,8 +1767,16 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
 
 /**
  * Prints the menus to add activities and resources.
+ *
+ * @param stdClass $course The course
+ * @param stdClass $section The section
+ * @param array $modnames An array containing the list of modules and their names
+ * @param bool $vertical Vertical orientation
+ * @param bool $return Return the menus or send them to output
+ * @param int $sectionreturn The section to link back to
+ * @return void|string depending on $return
  */
-function print_section_add_menus($course, $section, $modnames, $vertical=false, $return=false, $sectionreturn = false) {
+function print_section_add_menus($course, $section, $modnames, $vertical=false, $return=false, $sectionreturn=0) {
     global $CFG, $OUTPUT;
 
     // check to see if user can add menus
@@ -1779,14 +1792,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
     $activities = array();
 
     // We need to add the section section to the link for each module
-    $sectionlink = '&section=' . $section;
-
-    // We need to add the section to return to
-    if ($sectionreturn) {
-        $sectionreturnlink = '&sr=' . $section;
-    } else {
-        $sectionreturnlink = '&sr=0';
-    }
+    $sectionlink = '&section=' . $section . '&sr=' . $sectionreturn;
 
     foreach ($modules as $module) {
         if (isset($module->types)) {
@@ -1794,7 +1800,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
             // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!!
             $subtypes = array();
             foreach ($module->types as $subtype) {
-                $subtypes[$subtype->link . $sectionlink . $sectionreturnlink] = $subtype->title;
+                $subtypes[$subtype->link . $sectionlink] = $subtype->title;
             }
 
             // Sort module subtypes into the list
@@ -1816,11 +1822,11 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
         } else {
             // This module has no subtypes
             if ($module->archetype == MOD_ARCHETYPE_RESOURCE) {
-                $resources[$module->link . $sectionlink . $sectionreturnlink] = $module->title;
+                $resources[$module->link . $sectionlink] = $module->title;
             } else if ($module->archetype === MOD_ARCHETYPE_SYSTEM) {
                 // System modules cannot be added by user, do not add to dropdown
             } else {
-                $activities[$module->link . $sectionlink . $sectionreturnlink] = $module->title;
+                $activities[$module->link . $sectionlink] = $module->title;
             }
         }
     }
@@ -4032,7 +4038,7 @@ function average_number_of_participants() {
         WHERE ue.enrolid = e.id
             AND e.courseid <> :siteid
             AND c.id = e.courseid
-            AND c.visible = 1) as total';
+            AND c.visible = 1)';
     $params = array('siteid' => $SITE->id);
     $enrolmenttotal = $DB->count_records_sql($sql, $params);
 
@@ -4065,7 +4071,7 @@ function average_number_of_courses_modules() {
         WHERE c.id = cm.course
             AND c.id <> :siteid
             AND cm.visible = 1
-            AND c.visible = 1) as total';
+            AND c.visible = 1)';
     $params = array('siteid' => $SITE->id);
     $moduletotal = $DB->count_records_sql($sql, $params);
 
index 5bdee18..7b93b04 100644 (file)
@@ -53,7 +53,7 @@
 
 /// Get course
     if (!($course = $DB->get_record('course', array('id'=>$courseid)))) {
-        print_error('invalidcourseid', '', '', $courseid);
+        print_error('invalidcourseid');
     }
 
 /// Only SITE users can access to this page
index 2336d53..7f30c07 100644 (file)
@@ -70,7 +70,11 @@ class core_adodb_testcase extends advanced_testcase {
                 set_config('dbsetupsql', 'SET NAMES \'UTF-8\'', 'enrol_database');
                 set_config('dbsybasequoting', '0', 'enrol_database');
                 if (!empty($CFG->dboptions['dbsocket']) and ($CFG->dbhost === 'localhost' or $CFG->dbhost === '127.0.0.1')) {
-                    set_config('dbhost', $CFG->dboptions['dbsocket'], 'enrol_database');
+                    if (strpos($CFG->dboptions['dbsocket'], '/') !== false) {
+                      set_config('dbhost', $CFG->dboptions['dbsocket'], 'enrol_database');
+                    } else {
+                      set_config('dbhost', '', 'enrol_database');
+                    }
                 }
                 break;
 
index 2f84bc2..fe0baf9 100644 (file)
             fclose( $fh );
 
             // run latex on document
-            $command = "{$CFG->filter_tex_pathlatex} --interaction=nonstopmode $tex";
+            $command = "{$CFG->filter_tex_pathlatex} --interaction=nonstopmode --halt-on-error $tex";
             chdir( $this->temp_dir );
             if ($this->execute($command, $log)) { // It allways False on Windows
 //                return false;
index 35f1afb..b4a08de 100644 (file)
         chdir($latex->temp_dir);
 
         // step 1: latex command
-        $cmd = "$CFG->filter_tex_pathlatex --interaction=nonstopmode $tex";
+        $cmd = "$CFG->filter_tex_pathlatex --interaction=nonstopmode --halt-on-error $tex";
         $output .= execute($cmd);
 
         // step 2: dvips command
index 1530d2c..c736b23 100644 (file)
@@ -40,6 +40,8 @@ abstract class grade_export {
     public $displaytype; // display type (e.g. real, percentages, letter) for exports
     public $decimalpoints; // number of decimal points for exports
     public $onlyactive; // only include users with an active enrolment
+    public $usercustomfields; // include users custom fields
+
     /**
      * Constructor should set up all the private variables ready to be pulled
      * @access public
@@ -47,10 +49,14 @@ abstract class grade_export {
      * @param int $groupid id of selected group, 0 means all
      * @param string $itemlist comma separated list of item ids, empty means all
      * @param boolean $export_feedback
-     * @param boolean $export_letters
+     * @param boolean $updatedgradesonly
+     * @param string $displaytype
+     * @param int $decimalpoints
+     * @param boolean $onlyactive
+     * @param boolean $usercustomfields include user custom field in export
      * @note Exporting as letters will lead to data loss if that exported set it re-imported.
      */
-    public function grade_export($course, $groupid=0, $itemlist='', $export_feedback=false, $updatedgradesonly = false, $displaytype = GRADE_DISPLAY_TYPE_REAL, $decimalpoints = 2, $onlyactive = false) {
+    public function grade_export($course, $groupid=0, $itemlist='', $export_feedback=false, $updatedgradesonly = false, $displaytype = GRADE_DISPLAY_TYPE_REAL, $decimalpoints = 2, $onlyactive = false, $usercustomfields = false) {
         $this->course = $course;
         $this->groupid = $groupid;
         $this->grade_items = grade_item::fetch_all(array('courseid'=>$this->course->id));
@@ -85,6 +91,7 @@ abstract class grade_export {
         $this->displaytype = $displaytype;
         $this->decimalpoints = $decimalpoints;
         $this->onlyactive = $onlyactive;
+        $this->usercustomfields = $usercustomfields;
     }
 
     /**
@@ -205,16 +212,18 @@ abstract class grade_export {
      */
     public function display_preview($require_user_idnumber=false) {
         global $OUTPUT;
+
+        $userprofilefields = grade_helper::get_user_profile_fields($this->course->id, $this->usercustomfields);
+        $formatoptions = new stdClass();
+        $formatoptions->para = false;
+
         echo $OUTPUT->heading(get_string('previewrows', 'grades'));
 
         echo '<table>';
         echo '<tr>';
-        echo '<th>'.get_string("firstname")."</th>".
-             '<th>'.get_string("lastname")."</th>".
-             '<th>'.get_string("idnumber")."</th>".
-             '<th>'.get_string("institution")."</th>".
-             '<th>'.get_string("department")."</th>".
-             '<th>'.get_string("email")."</th>";
+        foreach ($userprofilefields as $field) {
+            echo '<th>' . $field->fullname . '</th>';
+        }
         foreach ($this->columns as $grade_item) {
             echo '<th>'.$this->format_column_name($grade_item).'</th>';
 
@@ -225,10 +234,10 @@ abstract class grade_export {
         }
         echo '</tr>';
         /// Print all the lines of data.
-
         $i = 0;
         $gui = new graded_users_iterator($this->course, $this->columns, $this->groupid);
         $gui->require_active_enrolment($this->onlyactive);
+        $gui->allow_user_custom_fields($this->usercustomfields);
         $gui->init();
         while ($userdata = $gui->next_user()) {
             // number of preview rows
@@ -269,7 +278,11 @@ abstract class grade_export {
             }
 
             echo '<tr>';
-            echo "<td>$user->firstname</td><td>$user->lastname</td><td>$user->idnumber</td><td>$user->institution</td><td>$user->department</td><td>$user->email</td>";
+            foreach ($userprofilefields as $field) {
+                $fieldvalue = grade_helper::get_user_field_value($user, $field);
+                // @see profile_field_base::display_data().
+                echo '<td>' . format_text($fieldvalue, FORMAT_MOODLE, $formatoptions) . '</td>';
+            }
             echo $rowstr;
             echo "</tr>";
 
@@ -298,7 +311,8 @@ abstract class grade_export {
                         'updatedgradesonly' =>$this->updatedgradesonly,
                         'displaytype'       =>$this->displaytype,
                         'decimalpoints'     =>$this->decimalpoints,
-                        'export_onlyactive' =>$this->onlyactive);
+                        'export_onlyactive' =>$this->onlyactive,
+                        'usercustomfields'  =>$this->usercustomfields);
 
         return $params;
     }
index 04a00e8..ae38b92 100644 (file)
@@ -45,7 +45,7 @@ if (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('
 }
 
 // print all the exported data here
-$export = new grade_export_ods($course, $groupid, $itemids, $export_feedback, $updatedgradesonly, $displaytype, $decimalpoints, $onlyactive);
+$export = new grade_export_ods($course, $groupid, $itemids, $export_feedback, $updatedgradesonly, $displaytype, $decimalpoints, $onlyactive, true);
 $export->print_grades();
 
 
index e366131..30fe2eb 100644 (file)
@@ -34,49 +34,48 @@ class grade_export_ods extends grade_export {
 
         $shortname = format_string($this->course->shortname, true, array('context' => get_context_instance(CONTEXT_COURSE, $this->course->id)));
 
-    /// Calculate file name
+        // Calculate file name
         $downloadfilename = clean_filename("$shortname $strgrades.ods");
-    /// Creating a workbook
+        // Creating a workbook
         $workbook = new MoodleODSWorkbook("-");
-    /// Sending HTTP headers
+        // Sending HTTP headers
         $workbook->send($downloadfilename);
-    /// Adding the worksheet
+        // Adding the worksheet
         $myxls =& $workbook->add_worksheet($strgrades);
 
-    /// Print names of all the fields
-        $myxls->write_string(0,0,get_string("firstname"));
-        $myxls->write_string(0,1,get_string("lastname"));
-        $myxls->write_string(0,2,get_string("idnumber"));
-        $myxls->write_string(0,3,get_string("institution"));
-        $myxls->write_string(0,4,get_string("department"));
-        $myxls->write_string(0,5,get_string("email"));
-        $pos=6;
+
+        // Print names of all the fields.
+        $profilefields = grade_helper::get_user_profile_fields($this->course->id, $this->usercustomfields);
+        foreach ($profilefields as $id => $field) {
+            $myxls->write_string(0, $id, $field->fullname);
+        }
+        $pos = count($profilefields);
         foreach ($this->columns as $grade_item) {
             $myxls->write_string(0, $pos++, $this->format_column_name($grade_item));
 
-            /// add a column_feedback column
+            // Add a column_feedback column.
             if ($this->export_feedback) {
                 $myxls->write_string(0, $pos++, $this->format_column_name($grade_item, true));
             }
         }
 
-    /// Print all the lines of data.
+        // Print all the lines of data.
         $i = 0;
         $geub = new grade_export_update_buffer();
         $gui = new graded_users_iterator($this->course, $this->columns, $this->groupid);
         $gui->require_active_enrolment($this->onlyactive);
+        $gui->allow_user_custom_fields($this->usercustomfields);
         $gui->init();
         while ($userdata = $gui->next_user()) {
             $i++;
             $user = $userdata->user;
 
-            $myxls->write_string($i,0,$user->firstname);
-            $myxls->write_string($i,1,$user->lastname);
-            $myxls->write_string($i,2,$user->idnumber);
-            $myxls->write_string($i,3,$user->institution);
-            $myxls->write_string($i,4,$user->department);
-            $myxls->write_string($i,5,$user->email);
-            $j=6;
+            foreach($profilefields as $id => $field) {
+                $fieldvalue = grade_helper::get_user_field_value($user, $field);
+                $myxls->write_string($i, $id, $fieldvalue);
+            }
+            $j = count($profilefields);
+
             foreach ($userdata->grades as $itemid => $grade) {
                 if ($export_tracking) {
                     $status = $geub->track($grade);
@@ -99,7 +98,7 @@ class grade_export_ods extends grade_export {
         $gui->close();
         $geub->close();
 
-    /// Close the workbook
+        // Close the workbook.
         $workbook->close();
 
         exit;
index 78cd116..0bb7068 100644 (file)
@@ -51,7 +51,7 @@ if ($groupmode == SEPARATEGROUPS and !$currentgroup and !has_capability('moodle/
 
 // process post information
 if ($data = $mform->get_data()) {
-    $export = new grade_export_ods($course, $currentgroup, '', false, false, $data->display, $data->decimals, $data->export_onlyactive);
+    $export = new grade_export_ods($course, $currentgroup, '', false, false, $data->display, $data->decimals, $data->export_onlyactive, true);
 
     // print the grades on screen for feedbacks
     $export->process_form($data);
index e5e572c..17108ee 100644 (file)
@@ -46,7 +46,7 @@ if (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('
 }
 
 // print all the exported data here
-$export = new grade_export_txt($course, $groupid, $itemids, $export_feedback, $updatedgradesonly, $displaytype, $decimalpoints, $separator, $onlyactive);
+$export = new grade_export_txt($course, $groupid, $itemids, $export_feedback, $updatedgradesonly, $displaytype, $decimalpoints, $separator, $onlyactive, true);
 $export->print_grades();
 
 
index 0be9589..43ee3db 100644 (file)
@@ -23,8 +23,20 @@ class grade_export_txt extends grade_export {
 
     public $separator; // default separator
 
-    public function __construct($course, $groupid=0, $itemlist='', $export_feedback=false, $updatedgradesonly = false, $displaytype = GRADE_DISPLAY_TYPE_REAL, $decimalpoints = 2, $separator = 'comma', $onlyactive = false) {
-        parent::__construct($course, $groupid, $itemlist, $export_feedback, $updatedgradesonly, $displaytype, $decimalpoints, $onlyactive);
+    /**
+     * Constructor should set up all the private variables ready to be pulled
+     * @param object $course
+     * @param int $groupid id of selected group, 0 means all
+     * @param string $itemlist comma separated list of item ids, empty means all
+     * @param boolean $export_feedback
+     * @param boolean $updatedgradesonly
+     * @param string $displaytype
+     * @param int $decimalpoints
+     * @param boolean $onlyactive
+     * @param boolean $usercustomfields include user custom field in export
+     */
+    public function __construct($course, $groupid=0, $itemlist='', $export_feedback=false, $updatedgradesonly = false, $displaytype = GRADE_DISPLAY_TYPE_REAL, $decimalpoints = 2, $separator = 'comma', $onlyactive = false, $usercustomfields = false) {
+        parent::__construct($course, $groupid, $itemlist, $export_feedback, $updatedgradesonly, $displaytype, $decimalpoints, $onlyactive, $usercustomfields);
         $this->separator = $separator;
     }
 
@@ -40,6 +52,7 @@ class grade_export_txt extends grade_export {
         $export_tracking = $this->track_exports();
 
         $strgrades = get_string('grades');
+        $profilefields = grade_helper::get_user_profile_fields($this->course->id, $this->usercustomfields);
 
         switch ($this->separator) {
             case 'comma':
@@ -50,7 +63,7 @@ class grade_export_txt extends grade_export {
                 $separator = "\t";
         }
 
-        /// Print header to force download
+        // Print header to force download
         if (strpos($CFG->wwwroot, 'https://') === 0) { //https sites - watch out for IE! KB812935 and KB316431
             @header('Cache-Control: max-age=10');
             @header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT');
@@ -65,34 +78,39 @@ class grade_export_txt extends grade_export {
         $downloadfilename = clean_filename("$shortname $strgrades");
         header("Content-Disposition: attachment; filename=\"$downloadfilename.txt\"");
 
-/// Print names of all the fields
-        echo get_string("firstname").$separator.
-             get_string("lastname").$separator.
-             get_string("idnumber").$separator.
-             get_string("institution").$separator.
-             get_string("department").$separator.
-             get_string("email");
+        // Print names of all the fields
+        $fieldfullnames = array();
+        foreach ($profilefields as $field) {
+            $fieldfullnames[] = $field->fullname;
+        }
+        echo implode($separator, $fieldfullnames);
 
         foreach ($this->columns as $grade_item) {
             echo $separator.$this->format_column_name($grade_item);
 
-            /// add a feedback column
+            // Add a feedback column.
             if ($this->export_feedback) {
                 echo $separator.$this->format_column_name($grade_item, true);
             }
         }
         echo "\n";
 
-/// Print all the lines of data.
+        // Print all the lines of data.
         $geub = new grade_export_update_buffer();
         $gui = new graded_users_iterator($this->course, $this->columns, $this->groupid);
         $gui->require_active_enrolment($this->onlyactive);
+        $gui->allow_user_custom_fields($this->usercustomfields);
         $gui->init();
         while ($userdata = $gui->next_user()) {
 
             $user = $userdata->user;
 
-            echo $user->firstname.$separator.$user->lastname.$separator.$user->idnumber.$separator.$user->institution.$separator.$user->department.$separator.$user->email;
+            $items = array();
+            foreach ($profilefields as $field) {
+                $fieldvalue = grade_helper::get_user_field_value($user, $field);
+                $items[] = $fieldvalue;
+            }
+            echo implode($separator, $items);
 
             foreach ($userdata->grades as $itemid => $grade) {
                 if ($export_tracking) {
index 7f5f842..edda839 100644 (file)
@@ -51,7 +51,7 @@ if ($groupmode == SEPARATEGROUPS and !$currentgroup and !has_capability('moodle/
 
 // process post information
 if ($data = $mform->get_data()) {
-    $export = new grade_export_txt($course, $currentgroup, '', false, false, $data->display, $data->decimals, $data->separator, $data->export_onlyactive);
+    $export = new grade_export_txt($course, $currentgroup, '', false, false, $data->display, $data->decimals, $data->separator, $data->export_onlyactive, true);
 
     // print the grades on screen for feedback
 
index 8526f3c..16601ab 100644 (file)
@@ -45,7 +45,7 @@ if (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('
 }
 
 // print all the exported data here
-$export = new grade_export_xls($course, $groupid, $itemids, $export_feedback, $updatedgradesonly, $displaytype, $decimalpoints, $onlyactive);
+$export = new grade_export_xls($course, $groupid, $itemids, $export_feedback, $updatedgradesonly, $displaytype, $decimalpoints, $onlyactive, true);
 $export->print_grades();
 
 
index a89c910..e907c48 100644 (file)
@@ -32,50 +32,49 @@ class grade_export_xls extends grade_export {
 
         $strgrades = get_string('grades');
 
-    /// Calculate file name
+        // Calculate file name
         $shortname = format_string($this->course->shortname, true, array('context' => get_context_instance(CONTEXT_COURSE, $this->course->id)));
         $downloadfilename = clean_filename("$shortname $strgrades.xls");
-    /// Creating a workbook
+        // Creating a workbook
         $workbook = new MoodleExcelWorkbook("-");
-    /// Sending HTTP headers
+        // Sending HTTP headers
         $workbook->send($downloadfilename);
-    /// Adding the worksheet
+        // Adding the worksheet
         $myxls =& $workbook->add_worksheet($strgrades);
 
-    /// Print names of all the fields
-        $myxls->write_string(0,0,get_string("firstname"));
-        $myxls->write_string(0,1,get_string("lastname"));
-        $myxls->write_string(0,2,get_string("idnumber"));
-        $myxls->write_string(0,3,get_string("institution"));
-        $myxls->write_string(0,4,get_string("department"));
-        $myxls->write_string(0,5,get_string("email"));
-        $pos=6;
+        // Print names of all the fields
+        $profilefields = grade_helper::get_user_profile_fields($this->course->id, $this->usercustomfields);
+        foreach ($profilefields as $id => $field) {
+            $myxls->write_string(0, $id, $field->fullname);
+        }
+        $pos = count($profilefields);
+
         foreach ($this->columns as $grade_item) {
             $myxls->write_string(0, $pos++, $this->format_column_name($grade_item));
 
-            /// add a column_feedback column
+            // Add a column_feedback column
             if ($this->export_feedback) {
                 $myxls->write_string(0, $pos++, $this->format_column_name($grade_item, true));
             }
         }
 
-    /// Print all the lines of data.
+        // Print all the lines of data.
         $i = 0;
         $geub = new grade_export_update_buffer();
         $gui = new graded_users_iterator($this->course, $this->columns, $this->groupid);
         $gui->require_active_enrolment($this->onlyactive);
+        $gui->allow_user_custom_fields($this->usercustomfields);
         $gui->init();
         while ($userdata = $gui->next_user()) {
             $i++;
             $user = $userdata->user;
 
-            $myxls->write_string($i,0,$user->firstname);
-            $myxls->write_string($i,1,$user->lastname);
-            $myxls->write_string($i,2,$user->idnumber);
-            $myxls->write_string($i,3,$user->institution);
-            $myxls->write_string($i,4,$user->department);
-            $myxls->write_string($i,5,$user->email);
-            $j=6;
+            foreach ($profilefields as $id => $field) {
+                $fieldvalue = grade_helper::get_user_field_value($user, $field);
+                $myxls->write_string($i, $id, $fieldvalue);
+            }
+            $j = count($profilefields);
+
             foreach ($userdata->grades as $itemid => $grade) {
                 if ($export_tracking) {
                     $status = $geub->track($grade);
index 68d7f67..a4ee256 100644 (file)
@@ -51,7 +51,7 @@ if ($groupmode == SEPARATEGROUPS and !$currentgroup and !has_capability('moodle/
 
 // process post information
 if ($data = $mform->get_data()) {
-    $export = new grade_export_xls($course, $currentgroup, '', false, false, $data->display, $data->decimals, $data->export_onlyactive);
+    $export = new grade_export_xls($course, $currentgroup, '', false, false, $data->display, $data->decimals, $data->export_onlyactive, true);
 
     // print the grades on screen for feedbacks
     $export->process_form($data);
index 9d1bda9..e5639ac 100644 (file)
@@ -88,6 +88,11 @@ class graded_users_iterator {
      */
     protected $onlyactive = false;
 
+    /**
+     * Enable user custom fields
+     */
+    protected $allowusercustomfields = false;
+
     /**
      * Constructor
      *
@@ -169,11 +174,29 @@ class graded_users_iterator {
             }
         }
 
+        $userfields = 'u.*';
+        $customfieldssql = '';
+        if ($this->allowusercustomfields && !empty($CFG->grade_export_customprofilefields)) {
+            $customfieldscount = 0;
+            $customfieldsarray = grade_helper::get_user_profile_fields($this->course->id, $this->allowusercustomfields);
+            foreach ($customfieldsarray as $field) {
+                if (!empty($field->customid)) {
+                    $customfieldssql .= "
+                            LEFT JOIN (SELECT * FROM {user_info_data}
+                                WHERE fieldid = :cf$customfieldscount) cf$customfieldscount
+                            ON u.id = cf$customfieldscount.userid";
+                    $userfields .= ", cf$customfieldscount.data AS 'customfield_{$field->shortname}'";
+                    $params['cf'.$customfieldscount] = $field->customid;
+                    $customfieldscount++;
+                }
+            }
+        }
+
         // $params contents: gradebookroles and groupid (for $groupwheresql)
-        $users_sql = "SELECT u.* $ofields
+        $users_sql = "SELECT $userfields $ofields
                         FROM {user} u
                         JOIN ($enrolledsql) je ON je.id = u.id
-                             $groupsql
+                             $groupsql $customfieldssql
                         JOIN (
                                   SELECT DISTINCT ra.userid
                                     FROM {role_assignments} ra
@@ -311,6 +334,19 @@ class graded_users_iterator {
         $this->onlyactive  = $onlyactive;
     }
 
+    /**
+     * Allow custom fields to be included
+     *
+     * @param bool $allow Whether to allow custom fields or not
+     * @return void
+     */
+    public function allow_user_custom_fields($allow = true) {
+        if ($allow) {
+            $this->allowusercustomfields = true;
+        } else {
+            $this->allowusercustomfields = false;
+        }
+    }
 
     /**
      * Add a grade_grade instance to the grade stack
@@ -2665,4 +2701,101 @@ abstract class grade_helper {
         }
         return self::$exportplugins;
     }
+
+    /**
+     * Returns the value of a field from a user record
+     *
+     * @param stdClass $user object
+     * @param stdClass $field object
+     * @return string value of the field
+     */
+    public static function get_user_field_value($user, $field) {
+        if (!empty($field->customid)) {
+            $fieldname = 'customfield_' . $field->shortname;
+            if (!empty($user->{$fieldname}) || is_numeric($user->{$fieldname})) {
+                $fieldvalue = $user->{$fieldname};
+            } else {
+                $fieldvalue = $field->default;
+            }
+        } else {
+            $fieldvalue = $user->{$field->shortname};
+        }
+        return $fieldvalue;
+    }
+
+    /**
+     * Returns an array of user profile fields to be included in export
+     *
+     * @param int $courseid
+     * @param bool $includecustomfields
+     * @return array An array of stdClass instances with customid, shortname, datatype, default and fullname fields
+     */
+    public static function get_user_profile_fields($courseid, $includecustomfields = false) {
+        global $CFG, $DB;
+
+        // Gets the fields that have to be hidden
+        $hiddenfields = array_map('trim', explode(',', $CFG->hiddenuserfields));
+        $context = context_course::instance($courseid);
+        $canseehiddenfields = has_capability('moodle/course:viewhiddenuserfields', $context);
+        if ($canseehiddenfields) {
+            $hiddenfields = array();
+        }
+
+        $fields = array();
+        require_once($CFG->dirroot.'/user/lib.php');                // Loads user_get_default_fields()
+        require_once($CFG->dirroot.'/user/profile/lib.php');        // Loads constants, such as PROFILE_VISIBLE_ALL
+        $userdefaultfields = user_get_default_fields();
+
+        // Sets the list of profile fields
+        $userprofilefields = array_map('trim', explode(',', $CFG->grade_export_userprofilefields));
+        if (!empty($userprofilefields)) {
+            foreach ($userprofilefields as $field) {
+                $field = trim($field);
+                if (in_array($field, $hiddenfields) || !in_array($field, $userdefaultfields)) {
+                    continue;
+                }
+                $obj = new stdClass();
+                $obj->customid  = 0;
+                $obj->shortname = $field;
+                $obj->fullname  = get_string($field);
+                $fields[] = $obj;
+            }
+        }
+
+        // Sets the list of custom profile fields
+        $customprofilefields = array_map('trim', explode(',', $CFG->grade_export_customprofilefields));
+        if ($includecustomfields && !empty($customprofilefields)) {
+            list($wherefields, $whereparams) = $DB->get_in_or_equal($customprofilefields);
+            $customfields = $DB->get_records_sql("SELECT f.*
+                                                    FROM {user_info_field} f
+                                                    JOIN {user_info_category} c ON f.categoryid=c.id
+                                                    WHERE f.shortname $wherefields
+                                                    ORDER BY c.sortorder ASC, f.sortorder ASC", $whereparams);
+            if (!is_array($customfields)) {
+                continue;
+            }
+
+            foreach ($customfields as $field) {
+                // Make sure we can display this custom field
+                if (!in_array($field->shortname, $customprofilefields)) {
+                    continue;
+                } else if (in_array($field->shortname, $hiddenfields)) {
+                    continue;
+                } else if ($field->visible != PROFILE_VISIBLE_ALL && !$canseehiddenfields) {
+                    continue;
+                }
+
+                $obj = new stdClass();
+                $obj->customid  = $field->id;
+                $obj->shortname = $field->shortname;
+                $obj->fullname  = format_string($field->name);
+                $obj->datatype  = $field->datatype;
+                $obj->default   = $field->defaultdata;
+                $fields[] = $obj;
+            }
+        }
+
+        return $fields;
+    }
 }
+
index 9a9d10c..8b73c59 100644 (file)
@@ -88,12 +88,12 @@ $string['yourprogress'] = 'Your progress';
 $string['achievinggrade']='Achieving grade';
 $string['activities']='Activities';
 $string['activitiescompleted']='Activities completed';
-$string['addcourseprerequisite']='Add course prerequisite';
 $string['afterspecifieddate']='After specified date';
 $string['aggregationmethod']='Aggregation method';
 $string['all']='All';
 $string['any']='Any';
 $string['approval']='Approval';
+$string['completiondependencies']='Completion dependencies';
 $string['completionenabled']='Enabled, control via completion and activity settings';
 $string['completionmenuitem']='Completion';
 $string['completiononunenrolment']='Completion on unenrolment';
@@ -106,7 +106,6 @@ $string['coursealreadycompleted']='You have already completed this course';
 $string['coursecomplete']='Course complete';
 $string['coursecompleted']='Course completed';
 $string['coursegrade']='Course grade';
-$string['courseprerequisites']='Course prerequisites';
 $string['coursesavailable']='Courses available';
 $string['coursesavailableexplaination']='<i>Course completion criteria must be set for a course to appear in this list</i>';
 $string['criteria']='Criteria';
@@ -115,6 +114,8 @@ $string['criteriagroup']='Criteria group';
 $string['criteriarequiredall']='All criteria below are required';
 $string['criteriarequiredany']='Any criteria below are required';
 $string['days']='Days';
+$string['dependencies']='Dependencies';
+$string['dependenciescompleted']='Dependencies completed';
 $string['editcoursecompletionsettings']='Edit course completion settings';
 $string['enrolmentduration']='Days left';
 $string['err_nocourses']='Course completion is not enabled for any other courses, so none can be displayed. You can enable course completion in the course settings.';
@@ -141,8 +142,6 @@ $string['notyetstarted']='Not yet started';
 $string['overallcriteriaaggregation']='Overall criteria type aggregation';
 $string['pending']='Pending';
 $string['periodpostenrolment']='Period post enrolment';
-$string['prerequisites']='Prerequisites';
-$string['prerequisitescompleted']='Prerequisites completed';
 $string['recognitionofpriorlearning']='Recognition of prior learning';
 $string['remainingenroledfortime']='Remaining enrolled for a specified period of time';
 $string['remainingenroleduntildate']='Remaining enrolled until a specified date';
index b40859b..7ad032c 100644 (file)
@@ -280,7 +280,7 @@ $string['invalidcomponent'] = 'Invalid component name';
 $string['invalidconfirmdata'] = 'Invalid confirmation data';
 $string['invalidcontext'] = 'Invalid context';
 $string['invalidcourse'] = 'Invalid course';
-$string['invalidcourseid'] = 'You are trying to use an invalid course ID: ({$a})';
+$string['invalidcourseid'] = 'You are trying to use an invalid course ID';
 $string['invalidcourselevel'] = 'Incorrect context level';
 $string['invalidcoursemodule'] = 'Invalid course module ID';
 $string['invalidcoursenameshort'] = 'Invalid short course name';
index 850e873..2c0b74f 100644 (file)
@@ -235,10 +235,14 @@ $string['gradedisplaytype_help'] = 'This setting determines how grades are displ
 * Letter - Letters or words are used to represent a range of grades';
 $string['gradedon'] = 'Graded: {$a}';
 $string['gradeexport'] = 'Grade export';
+$string['gradeexportcustomprofilefields'] = 'Grade export custom profile fields';
+$string['gradeexportcustomprofilefields_desc'] = 'Include these custom profile fields in the grade export, separated by commas.';
 $string['gradeexportdecimalpoints'] = 'Grade export decimal points';
 $string['gradeexportdecimalpoints_desc'] = 'The number of decimal points to display for export. This can be overridden during export.';
 $string['gradeexportdisplaytype'] = 'Grade export display type';
 $string['gradeexportdisplaytype_desc'] = 'Grades can be shown as real grades, as percentages (in reference to the minimum and maximum grades) or as letters (A, B, C etc..) during export. This can be overridden during export.';
+$string['gradeexportuserprofilefields'] = 'Grade export user profile fields';
+$string['gradeexportuserprofilefields_desc'] = 'Include these user profile fields in the grade export, separated by commas.';
 $string['gradeforstudent'] = '{$a->student}<br />{$a->item}{$a->feedback}';
 $string['gradehelp'] = 'Grade help';
 $string['gradehistorylifetime'] = 'Grade history lifetime';
index 49dbf0e..bffe068 100644 (file)
@@ -37,7 +37,6 @@ $string['deletenotes'] = 'Delete all notes';
 $string['editnote'] = 'Edit note';
 $string['enablenotes'] = 'Enable notes';
 $string['groupaddnewnote'] = 'Add a common note';
-$string['invalidcourseid'] = 'Invalid course id: {$a}';
 $string['invalidid'] = 'Invalid note ID specified';
 $string['invaliduserid'] = 'Invalid user id: {$a}';
 $string['nocontent'] = 'Note content can not be empty';
index 2578704..29fe2ed 100644 (file)
@@ -305,6 +305,7 @@ $string['role:assign'] = 'Assign roles to users';
 $string['roleassignments'] = 'Role assignments';
 $string['roledefinitions'] = 'Role definitions';
 $string['rolefullname'] = 'Role name';
+$string['roleincontext'] = '{$a->role} in {$a->context}';
 $string['role:manage'] = 'Create and manage roles';
 $string['role:override'] = 'Override permissions for others';
 $string['role:review'] = 'Review permissions for others';
@@ -315,6 +316,7 @@ $string['roles_help'] = 'A role is a collection of permissions defined for the w
 $string['roles_link'] = 'roles';
 $string['role:safeoverride'] = 'Override safe permissions for others';
 $string['roleselect'] = 'Select role';
+$string['rolesforuser'] = 'Roles for user {$a}';
 $string['roleshortname'] = 'Short name';
 $string['roleshortname_help'] = 'Role short name is a low level role identifier in which only ASCII alphanumeric characters are allowed. Do not change short names of standard roles.';
 $string['role:switchroles'] = 'Switch to other roles';
index 93e7ef8..c1125a1 100644 (file)
@@ -3052,6 +3052,53 @@ function get_user_roles(context $context, $userid = 0, $checkparentcontexts = tr
     return $DB->get_records_sql($sql ,$params);
 }
 
+/**
+ * Like get_user_roles, but adds in the authenticated user role, and the front
+ * page roles, if applicable.
+ *
+ * @param context $context the context.
+ * @param int $userid optional. Defaults to $USER->id
+ * @return array of objects with fields ->userid, ->contextid and ->roleid.
+ */
+function get_user_roles_with_special(context $context, $userid = 0) {
+    global $CFG, $USER;
+
+    if (empty($userid)) {
+        if (empty($USER->id)) {
+            return array();
+        }
+        $userid = $USER->id;
+    }
+
+    $ras = get_user_roles($context, $userid);
+
+    // Add front-page role if relevant.
+    $defaultfrontpageroleid = isset($CFG->defaultfrontpageroleid) ? $CFG->defaultfrontpageroleid : 0;
+    $isfrontpage = ($context->contextlevel == CONTEXT_COURSE && $context->instanceid == SITEID) ||
+            is_inside_frontpage($context);
+    if ($defaultfrontpageroleid && $isfrontpage) {
+        $frontpagecontext = context_course::instance(SITEID);
+        $ra = new stdClass();
+        $ra->userid = $userid;
+        $ra->contextid = $frontpagecontext->id;
+        $ra->roleid = $defaultfrontpageroleid;
+        $ras[] = $ra;
+    }
+
+    // Add authenticated user role if relevant.
+    $defaultuserroleid      = isset($CFG->defaultuserroleid) ? $CFG->defaultuserroleid : 0;
+    if ($defaultuserroleid && !isguestuser($userid)) {
+        $systemcontext = context_system::instance();
+        $ra = new stdClass();
+        $ra->userid = $userid;
+        $ra->contextid = $systemcontext->id;
+        $ra->roleid = $defaultuserroleid;
+        $ras[] = $ra;
+    }
+
+    return $ras;
+}
+
 /**
  * Creates a record in the role_allow_override table
  *
@@ -4275,6 +4322,15 @@ function role_get_description(stdClass $role) {
     }
 }
 
+/**
+ * Get all the localised role names for a context.
+ * @param context $context the context
+ * @param array of role objects with a ->localname field containing the context-specific role name.
+ */
+function role_get_names(context $context) {
+    return role_fix_names(get_all_roles(), $context);
+}
+
 /**
  * Prepare list of roles for display, apply aliases and format text
  *
index a25dea2..3fc19db 100644 (file)
@@ -123,7 +123,7 @@ class completion_criteria_course extends completion_criteria {
      * @return string
      */
     public function get_title() {
-        return get_string('prerequisitescompleted', 'completion');
+        return get_string('dependenciescompleted', 'completion');
     }
 
     /**
@@ -146,7 +146,7 @@ class completion_criteria_course extends completion_criteria {
      * @return string
      */
     public function get_type_title() {
-        return get_string('prerequisites', 'completion');
+        return get_string('dependencies', 'completion');
     }
 
     /**
index 3645c06..bf2a646 100644 (file)
@@ -377,10 +377,11 @@ function completion_cron_completions() {
         SET
             reaggregate = 0
         WHERE
-            reaggregate < {$timestarted}
+            reaggregate < :timestarted
+        AND reaggregate > 0
     ";
 
-    $DB->execute($sql);
+    $DB->execute($sql, array('timestarted' => $timestarted));
 }
 
 /**
index 2e5fb0c..e54cf89 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="lib/db" VERSION="20120709" COMMENT="XMLDB file for core Moodle tables"
+<XMLDB PATH="lib/db" VERSION="20120717" COMMENT="XMLDB file for core Moodle tables"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
 >
     <TABLE NAME="role" COMMENT="moodle roles" PREVIOUS="post" NEXT="context">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="name"/>
-        <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" COMMENT="Empty names are automatically localised" NEXT="shortname"/>
+        <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="Empty names are automatically localised" PREVIOUS="id" NEXT="shortname"/>
         <FIELD NAME="shortname" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="shortname" COMMENT="Empty descriptions may be automatically localised" NEXT="sortorder"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Empty descriptions may be automatically localised" PREVIOUS="shortname" NEXT="sortorder"/>
         <FIELD NAME="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="archetype"/>
         <FIELD NAME="archetype" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false" COMMENT="Role archetype is used during install and role reset, marks admin role and helps in site settings" PREVIOUS="sortorder"/>
       </FIELDS>
       </KEYS>
     </TABLE>
   </TABLES>
-</XMLDB>
+</XMLDB>
\ No newline at end of file
index 4df607a..cf9acb0 100644 (file)
@@ -534,6 +534,15 @@ $functions = array(
         'capabilities'=> 'moodle/category:manage',
     ),
 
+    'core_course_import_course' => array(
+        'classname'   => 'core_course_external',
+        'methodname'  => 'import_course',
+        'classpath'   => 'course/externallib.php',
+        'description' => 'Import course data from a course into another course. Does not include any user data.',
+        'type'        => 'write',
+        'capabilities'=> 'moodle/backup:backuptargetimport, moodle/restore:restoretargetimport',
+    ),
+
     // === message related functions ===
 
     'moodle_message_send_instantmessages' => array(
index 6ae310f..bbd6de2 100644 (file)
@@ -117,23 +117,25 @@ class mysql_sql_generator extends sql_generator {
      * by any of its comments, indexes and sequence creation SQL statements.
      */
     public function getCreateTableSQL($xmldb_table) {
-        // first find out if want some special db engine
-        $engine = null;
-        if (method_exists($this->mdb, 'get_dbengine')) {
-            $engine = $this->mdb->get_dbengine();
-        }
+        // First find out if want some special db engine.
+        $engine = $this->mdb->get_dbengine();
+        // Do we know collation?
+        $collation = $this->mdb->get_dbcollation();
 
         $sqlarr = parent::getCreateTableSQL($xmldb_table);
 
-        if (!$engine) {
-            // we rely on database defaults
-            return $sqlarr;
-        }
-
-        // let's inject the engine into SQL
+        // Let's inject the extra MySQL tweaks.
         foreach ($sqlarr as $i=>$sql) {
             if (strpos($sql, 'CREATE TABLE ') === 0) {
-                $sqlarr[$i] .= " ENGINE = $engine";
+                if ($engine) {
+                    $sqlarr[$i] .= " ENGINE = $engine";
+                }
+                if ($collation) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $sqlarr[$i] .= " DEFAULT CHARACTER SET utf8";
+                    }
+                    $sqlarr[$i] .= " DEFAULT COLLATE = $collation";
+                }
             }
         }
 
@@ -148,9 +150,26 @@ class mysql_sql_generator extends sql_generator {
      * @return array of sql statements
      */
     public function getCreateTempTableSQL($xmldb_table) {
+        // Do we know collation?
+        $collation = $this->mdb->get_dbcollation();
         $this->temptables->add_temptable($xmldb_table->getName());
-        $sqlarr = parent::getCreateTableSQL($xmldb_table); // we do not want the engine hack included in create table SQL
-        $sqlarr = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE TEMPORARY TABLE $1', $sqlarr);
+
+        $sqlarr = parent::getCreateTableSQL($xmldb_table);
+
+        // Let's inject the extra MySQL tweaks.
+        foreach ($sqlarr as $i=>$sql) {
+            if (strpos($sql, 'CREATE TABLE ') === 0) {
+                // We do not want the engine hack included in create table SQL.
+                $sqlarr[$i] = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE TEMPORARY TABLE $1', $sql);
+                if ($collation) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $sqlarr[$i] .= " DEFAULT CHARACTER SET utf8";
+                    }
+                    $sqlarr[$i] .= " DEFAULT COLLATE $collation";
+                }
+            }
+        }
+
         return $sqlarr;
     }
 
@@ -231,9 +250,21 @@ class mysql_sql_generator extends sql_generator {
                     $xmldb_length='255';
                 }
                 $dbtype .= '(' . $xmldb_length . ')';
+                if ($collation = $this->mdb->get_dbcollation()) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $dbtype .= " CHARACTER SET utf8";
+                    }
+                    $dbtype .= " COLLATE $collation";
+                }
                 break;
             case XMLDB_TYPE_TEXT:
                 $dbtype = 'LONGTEXT';
+                if ($collation = $this->mdb->get_dbcollation()) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $dbtype .= " CHARACTER SET utf8";
+                    }
+                    $dbtype .= " COLLATE $collation";
+                }
                 break;
             case XMLDB_TYPE_BINARY:
                 $dbtype = 'LONGBLOB';
@@ -333,18 +364,14 @@ class mysql_sql_generator extends sql_generator {
      */
     public function isNameInUse($object_name, $type, $table_name) {
 
-        // Calculate the real table name
-        $xmldb_table = new xmldb_table($table_name);
-        $tname = $this->getTableName($xmldb_table);
-
         switch($type) {
             case 'ix':
             case 'uix':
                 // First of all, check table exists
                 $metatables = $this->mdb->get_tables();
-                if (isset($metatables[$tname])) {
+                if (isset($metatables[$table_name])) {
                     // Fetch all the indexes in the table
-                    if ($indexes = $this->mdb->get_indexes($tname)) {
+                    if ($indexes = $this->mdb->get_indexes($table_name)) {
                         // Look for existing index in array
                         if (isset($indexes[$object_name])) {
                             return true;
index bf07322..b23ea27 100644 (file)
@@ -82,7 +82,13 @@ class mysqli_native_moodle_database extends moodle_database {
             throw new dml_connection_exception($dberr);
         }
 
-        $result = $conn->query("CREATE DATABASE $dbname DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci");
+        if (isset($dboptions['dbcollation']) and strpos($dboptions['dbcollation'], 'utf8_') === 0) {
+            $collation = $dboptions['dbcollation'];
+        } else {
+            $collation = 'utf8_unicode_ci';
+        }
+
+        $result = $conn->query("CREATE DATABASE $dbname DEFAULT CHARACTER SET utf8 DEFAULT COLLATE ".$collation);
 
         $conn->close();
 
@@ -146,22 +152,28 @@ class mysqli_native_moodle_database extends moodle_database {
             return $this->dboptions['dbengine'];
         }
 
+        if ($this->external) {
+            return null;
+        }
+
         $engine = null;
 
-        if (!$this->external) {
-            // look for current engine of our config table (the first table that gets created),
-            // so that we create all tables with the same engine
-            $sql = "SELECT engine FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = '{$this->prefix}config'";
-            $this->query_start($sql, NULL, SQL_QUERY_AUX);
-            $result = $this->mysqli->query($sql);
-            $this->query_end($result);
-            if ($rec = $result->fetch_assoc()) {
-                $engine = $rec['engine'];
-            }
-            $result->close();
+        // Look for current engine of our config table (the first table that gets created),
+        // so that we create all tables with the same engine.
+        $sql = "SELECT engine
+                  FROM INFORMATION_SCHEMA.TABLES
+                 WHERE table_schema = DATABASE() AND table_name = '{$this->prefix}config'";
+        $this->query_start($sql, NULL, SQL_QUERY_AUX);
+        $result = $this->mysqli->query($sql);
+        $this->query_end($result);
+        if ($rec = $result->fetch_assoc()) {
+            $engine = $rec['engine'];
         }
+        $result->close();
 
         if ($engine) {
+            // Cache the result to improve performance.
+            $this->dboptions['dbengine'] = $engine;
             return $engine;
         }
 
@@ -175,7 +187,7 @@ class mysqli_native_moodle_database extends moodle_database {
         }
         $result->close();
 
-        if (!$this->external and $engine === 'MyISAM') {
+        if ($engine === 'MyISAM') {
             // we really do not want MyISAM for Moodle, InnoDB or XtraDB is a reasonable defaults if supported
             $sql = "SHOW STORAGE ENGINES";
             $this->query_start($sql, NULL, SQL_QUERY_AUX);
@@ -196,9 +208,77 @@ class mysqli_native_moodle_database extends moodle_database {
             }
         }
 
+        // Cache the result to improve performance.
+        $this->dboptions['dbengine'] = $engine;
         return $engine;
     }
 
+    /**
+     * Returns the current MySQL db collation.
+     *
+     * This is an ugly workaround for MySQL default collation problems.
+     *
+     * @return string or null MySQL collation name
+     */
+    public function get_dbcollation() {
+        if (isset($this->dboptions['dbcollation'])) {
+            return $this->dboptions['dbcollation'];
+        }
+        if ($this->external) {
+            return null;
+        }
+
+        $collation = null;
+
+        // Look for current collation of our config table (the first table that gets created),
+        // so that we create all tables with the same collation.
+        $sql = "SELECT collation_name
+                  FROM INFORMATION_SCHEMA.COLUMNS
+                 WHERE table_schema = DATABASE() AND table_name = '{$this->prefix}config' AND column_name = 'value'";
+        $this->query_start($sql, NULL, SQL_QUERY_AUX);
+        $result = $this->mysqli->query($sql);
+        $this->query_end($result);
+        if ($rec = $result->fetch_assoc()) {
+            $collation = $rec['collation_name'];
+        }
+        $result->close();
+
+        if (!$collation) {
+            // Get the default database collation, but only if using UTF-8.
+            $sql = "SELECT @@collation_database";
+            $this->query_start($sql, NULL, SQL_QUERY_AUX);
+            $result = $this->mysqli->query($sql);
+            $this->query_end($result);
+            if ($rec = $result->fetch_assoc()) {
+                if (strpos($rec['@@collation_database'], 'utf8_') === 0) {
+                    $collation = $rec['@@collation_database'];
+                }
+            }
+            $result->close();
+        }
+
+        if (!$collation) {
+            // We want only utf8 compatible collations.
+            $collation = null;
+            $sql = "SHOW COLLATION WHERE Collation LIKE 'utf8\_%' AND Charset = 'utf8'";
+            $this->query_start($sql, NULL, SQL_QUERY_AUX);
+            $result = $this->mysqli->query($sql);
+            $this->query_end($result);
+            while ($res = $result->fetch_assoc()) {
+                $collation = $res['Collation'];
+                if (strtoupper($res['Default']) === 'YES') {
+                    $collation = $res['Collation'];
+                    break;
+                }
+            }
+            $result->close();
+        }
+
+        // Cache the result to improve performance.
+        $this->dboptions['dbcollation'] = $collation;
+        return $collation;
+    }
+
     /**
      * Returns localised database type name
      * Note: can be used before connect()
index 01a37e7..d8abda4 100644 (file)
@@ -1,3 +1,4 @@
 #dateselector-calendar-panel {background-color:#999;border-bottom:3px solid #999;border-right:3px solid #999;}
 #dateselector-calendar-content {border:1px solid #666;margin-top:-3px;margin-left:-3px;}
+#dateselector-calendar-content_t th.calweekdaycell {padding-left:3px; padding-right:3px;}
 body.ie #dateselector-calendar-panel.yui3-overlay-hidden table {display:none;}
\ No newline at end of file
index d403547..1109b22 100644 (file)
@@ -197,7 +197,30 @@ YUI.add('moodle-form-dateselector', function(Y) {
             this.calendar = new YAHOO.widget.Calendar(document.getElementById('dateselector-calendar-content'), {
                 iframe: false,
                 hide_blank_weeks: true,
-                start_weekday: config.firstdayofweek
+                start_weekday: config.firstdayofweek,
+                locale_weekdays: 'medium',
+                locale_months: 'long',
+                WEEKDAYS_MEDIUM: [
+                    config.sun,
+                    config.mon,
+                    config.tue,
+                    config.wed,
+                    config.thu,
+                    config.fri,
+                    config.sat ],
+                MONTHS_LONG: [
+                    config.january,
+                    config.february,
+                    config.march,
+                    config.april,
+                    config.may,
+                    config.june,
+                    config.july,
+                    config.august,
+                    config.september,
+                    config.october,
+                    config.november,
+                    config.december ],
             });
             this.calendar.changePageEvent.subscribe(function(){
                 this.fix_position();
index 8452790..7200379 100644 (file)
@@ -79,7 +79,28 @@ function form_init_date_js() {
     if (!$done) {
         $module   = 'moodle-form-dateselector';
         $function = 'M.form.dateselector.init_date_selectors';
-        $config = array(array('firstdayofweek'=>get_string('firstdayofweek', 'langconfig')));
+        $config = array(array(
+            'firstdayofweek'    =>  get_string('firstdayofweek', 'langconfig'),
+            'mon'               => strftime('%a', 360000),      // 5th Jan 1970 at 12pm
+            'tue'               => strftime('%a', 446400),
+            'wed'               => strftime('%a', 532800),
+            'thu'               => strftime('%a', 619200),
+            'fri'               => strftime('%a', 705600),
+            'sat'               => strftime('%a', 792000),
+            'sun'               => strftime('%a', 878400),
+            'january'           => strftime('%B', 14400),       // 1st Jan 1970 at 12pm
+            'february'          => strftime('%B', 2692800),
+            'march'             => strftime('%B', 5112000),
+            'april'             => strftime('%B', 7790400),
+            'may'               => strftime('%B', 10382400),
+            'june'              => strftime('%B', 13060800),
+            'july'              => strftime('%B', 15652800),
+            'august'            => strftime('%B', 18331200),
+            'september'         => strftime('%B', 21009600),
+            'october'           => strftime('%B', 23601600),
+            'november'          => strftime('%B', 26280000),
+            'december'          => strftime('%B', 28872000)
+        ));
         $PAGE->requires->yui_module($module, $function, $config);
         $done = true;
     }
@@ -408,19 +429,6 @@ abstract class moodleform {
         $this->_form->setDefaults($default_values);
     }
 
-    /**
-     * Sets file upload manager
-     *
-     * @deprecated since Moodle 2.0 Please don't used this API
-     * @todo MDL-31300 this api will be removed.
-     * @see MoodleQuickForm_filepicker
-     * @see MoodleQuickForm_filemanager
-     * @param bool $um upload manager
-     */
-    function set_upload_manager($um=false) {
-        debugging('Old file uploads can not be used any more, please use new filepicker element');
-    }
-
     /**
      * Check that form was submitted. Does not check validity of submitted data.
      *
index 6bf2e28..66af621 100644 (file)
@@ -1771,14 +1771,27 @@ M.util.load_flowplayer = function() {
 
             var rule;
             for (var j=0; j < document.styleSheets.length; j++) {
-                if (typeof (document.styleSheets[j].rules) != 'undefined') {
-                    var allrules = document.styleSheets[j].rules;
-                } else if (typeof (document.styleSheets[j].cssRules) != 'undefined') {
-                    var allrules = document.styleSheets[j].cssRules;
-                } else {
-                    // why??
+
+                // To avoid javascript security violation accessing cross domain stylesheets
+                var allrules = false;
+                try {
+                    if (typeof (document.styleSheets[j].rules) != 'undefined') {
+                        allrules = document.styleSheets[j].rules;
+                    } else if (typeof (document.styleSheets[j].cssRules) != 'undefined') {
+                        allrules = document.styleSheets[j].cssRules;
+                    } else {
+                        // why??
+                        continue;
+                    }
+                } catch (e) {
                     continue;
                 }
+
+                // On cross domain style sheets Chrome V8 allows access to rules but returns null
+                if (!allrules) {
+                    continue;
+                }
+
                 for(var i=0; i<allrules.length; i++) {
                     rule = '';
                     if (/^\.mp3flowplayer_.*Color$/.test(allrules[i].selectorText)) {
index 82b3ad9..c14929a 100644 (file)
@@ -1431,6 +1431,7 @@ class global_navigation extends navigation_node {
                 $function($this);
             } else if (function_exists($oldfunction)) {
                 // We continue to support the old function name to ensure backwards compatability
+                debugging("Deprecated local plugin navigation callback: Please rename '{$oldfunction}' to '{$function}'. Support for the old callback will be dropped after the release of 2.4", DEBUG_DEVELOPER);
                 $oldfunction($this);
             }
         }
index dc819aa..5c46983 100644 (file)
@@ -43,6 +43,10 @@ YUI.add('moodle-core-formchangechecker',
                  * get_form_dirty_state function later.
                  */
                 store_initial_value : function(e) {
+                    if (e.target.hasClass('ignoredirty')) {
+                        // Don't warn on elements with the ignoredirty class
+                        return;
+                    }
                     if (M.core_formchangechecker.get_form_dirty_state()) {
                         // Clear the store_initial_value listeners as the form is already dirty so
                         // we no longer need to call this function
@@ -88,7 +92,11 @@ YUI.add('moodle-core-formchangechecker',
         /**
          * Set the form changed state to true
          */
-        M.core_formchangechecker.set_form_changed = function() {
+        M.core_formchangechecker.set_form_changed = function(e) {
+            if (e.target.hasClass('ignoredirty')) {
+                // Don't warn on elements with the ignoredirty class
+                return;
+            }
             M.core_formchangechecker.stateinformation.formchanged = 1;
 
             // Once the form has been marked as dirty, we no longer need to keep track of form elements
index 251cff5..47b6d89 100644 (file)
@@ -206,7 +206,7 @@ $string['sendsubmissionreceipts_help'] = 'This switch will enable submission rec
 $string['settings'] = 'Assignment settings';
 $string['showrecentsubmissions'] = 'Show recent submissions';
 $string['submissiondrafts'] = 'Require students click submit button';
-$string['submissiondrafts_help'] = 'If enabled, students will have to click a Submit button to declare their submission as final. This allows students to keep a draft version of the submission on the system.';
+$string['submissiondrafts_help'] = 'If enabled, students will have to click a Submit button to declare their submission as final. This allows students to keep a draft version of the submission on the system. If this setting is changed from "No" to "Yes" after students have already submitted those submissions will be regarded as final.';
 $string['submissionnotready'] = 'This assignment is not ready to submit:';
 $string['submissionplugins'] = 'Submission plugins';
 $string['submissionreceipts'] = 'Send submission receipts';
index 2fef79b..85ff77e 100644 (file)
@@ -1744,7 +1744,7 @@ class assign {
         if (!empty($CFG->enableplagiarism)) {
             /** Include plagiarismlib.php */
             require_once($CFG->libdir . '/plagiarismlib.php');
-            plagiarism_update_status($this->get_course(), $this->get_course_module());
+            $o .= plagiarism_update_status($this->get_course(), $this->get_course_module());
         }
 
         $actionformtext = $this->output->render($gradingactions);
@@ -1808,11 +1808,8 @@ class assign {
         if (!empty($CFG->enableplagiarism)) {
             /** Include plagiarismlib.php */
             require_once($CFG->libdir . '/plagiarismlib.php');
-            ob_start();
 
-            plagiarism_print_disclosure($this->get_course_module()->id);
-            $o = ob_get_contents();
-            ob_end_clean();
+            $o .= plagiarism_print_disclosure($this->get_course_module()->id);
         }
 
         return $o;
index 187bc9a..95e2cfb 100644 (file)
@@ -50,8 +50,8 @@ if ($ADMIN->fulltree) {
 
     // The default here is feedback_comments (if it exists)
     $settings->add(new admin_setting_configselect('assign/feedback_plugin_for_gradebook',
-                   new lang_string('feedbackpluginforgradebook', 'mod_assign'),
-                   new lang_string('feedbackplugin', 'mod_assign'), 'assignfeedback_comments', $menu));
+                   new lang_string('feedbackplugin', 'mod_assign'),
+                   new lang_string('feedbackpluginforgradebook', 'mod_assign'), 'assignfeedback_comments', $menu));
     $settings->add(new admin_setting_configcheckbox('assign/showrecentsubmissions',
                    new lang_string('showrecentsubmissions', 'assign'),
                    new lang_string('configshowrecentsubmissions', 'assign'), 0));
index 8f8dcf3..eea2714 100644 (file)
@@ -1591,7 +1591,7 @@ class assignment_base {
                     }
                     $currentposition++;
                 }
-                if ($hassubmission && ($this->assignment->assignmenttype=='upload' || $this->assignment->assignmenttype=='online' || $this->assignment->assignmenttype=='uploadsingle')) { //TODO: this is an ugly hack, where is the plugin spirit? (skodak)
+                if ($hassubmission && method_exists($this, 'download_submissions')) {
                     echo html_writer::start_tag('div', array('class' => 'mod-assignment-download-link'));
                     echo html_writer::link(new moodle_url('/mod/assignment/submissions.php', array('id' => $this->cm->id, 'download' => 'zip')), get_string('downloadall', 'assignment'));
                     echo html_writer::end_tag('div');
index 48819c7..0ef8de8 100644 (file)
@@ -107,6 +107,11 @@ class assignment_online extends assignment_base {
             } else {
                 echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter', 'online');
                 if ($submission && has_capability('mod/assignment:exportownsubmission', $this->context)) {
+                    echo plagiarism_get_links(array('userid' => $USER->id,
+                        'content' => trim(format_text($submission->data1, $submission->data2, array('context' => $context))),
+                        'cmid' => $this->cm->id,
+                        'course' => $this->course,
+                        'assignment' => $this->assignment));
                     $text = file_rewrite_pluginfile_urls($submission->data1, 'pluginfile.php', $this->context->id, 'mod_assignment', $this->filearea, $submission->id);
                     echo format_text($text, $submission->data2, array('overflowdiv'=>true));
                     if ($CFG->enableportfolios) {
@@ -194,6 +199,21 @@ class assignment_online extends assignment_base {
 
         $submission = $this->get_submission($USER->id);
         $this->update_grade($submission);
+        $fs = get_file_storage();
+        $files = $fs->get_area_files($this->context->id, 'mod_assignment', 'submission', $submission->id);
+        // Let Moodle know that an assessable content was uploaded (eg for plagiarism detection)
+        $eventdata = new stdClass();
+        $eventdata->modulename   = 'assignment';
+        $eventdata->name         = 'update_submission';
+        $eventdata->cmid         = $this->cm->id;
+        $eventdata->itemid       = $update->id;
+        $eventdata->courseid     = $this->course->id;
+        $eventdata->userid       = $USER->id;
+        $eventdata->content      = trim(format_text($update->data1, $update->data2));
+        if ($files) {
+            $eventdata->pathnamehashes = array_keys($files);
+        }
+        events_trigger('assessable_content_uploaded', $eventdata);
         return $submission;
     }
 
@@ -211,6 +231,11 @@ class assignment_online extends assignment_base {
         $output = '<div class="files">'.
                   $OUTPUT->pix_icon(file_extension_icon('.htm'), 'html', 'moodle', array('class' => 'icon')).
                   $popup .
+                  plagiarism_get_links(array('userid' => $userid,
+                      'content' => trim(format_text($submission->data1, $submission->data2)),
+                      'cmid' => $this->cm->id,
+                      'course' => $this->course,
+                      'assignment' => $this->assignment)) .
                   '</div>';
                   return $output;
     }
@@ -284,6 +309,9 @@ class assignment_online extends assignment_base {
         $mform->addHelpButton('var1', 'commentinline', 'assignment');
         $mform->setDefault('var1', 0);
 
+        $coursecontext = context_course::instance($COURSE->id);
+        plagiarism_get_form_elements_module($mform, $coursecontext);
+
     }
 
     function portfolio_exportable() {
index 71c0241..fc48974 100644 (file)
@@ -247,11 +247,11 @@ M.mod_chat_ajax.init = function(Y, cfg) {
                     li.all('td').item(1).append(Y.Node.create('<strong><a target="_blank" href="'+users[i].url+'">'+ users[i].name+'</a></strong>'));
                 } else {
                     li.all('td').item(1).append(Y.Node.create('<div><a target="_blank" href="'+users[i].url+'">'+users[i].name+'</a></div>'));
-                    var talk = Y.Node.create('<a href="###">'+M.str.chat.talk+'</a>&nbsp;');
+                    var talk = Y.Node.create('<a href="###">'+M.str.chat.talk+'</a>');
                     talk.on('click', this.talkto, this, users[i].name);
                     var beep = Y.Node.create('<a href="###">'+M.str.chat.beep+'</a>');
                     beep.on('click', this.send, this, users[i].id);
-                    li.all('td').item(1).append(Y.Node.create('<div></div>').append(talk).append(beep));
+                    li.all('td').item(1).append(Y.Node.create('<div></div>').append(talk).append('&nbsp;').append(beep));
                 }
                 list.append(li);
             }
index 07bbd19..ccbb949 100644 (file)
@@ -213,15 +213,17 @@ class mod_choice_renderer extends plugin_renderer_base {
                             $user->imagealt = '';
                         }
 
+                        $userfullname = fullname($user, $choices->fullnamecapability);
                         if ($choices->viewresponsecapability && $choices->deleterepsonsecapability  && $optionid > 0) {
-                            $attemptaction = html_writer::checkbox('attemptid[]', $user->id,'');
+                            $attemptaction = html_writer::label($userfullname, 'attempt-user'.$user->id, false, array('class' => 'accesshide'));
+                            $attemptaction .= html_writer::checkbox('attemptid[]', $user->id,'', null, array('id' => 'attempt-user'.$user->id));
                             $data .= html_writer::tag('div', $attemptaction, array('class'=>'attemptaction'));
                         }
                         $userimage = $this->output->user_picture($user, array('courseid'=>$choices->courseid));
                         $data .= html_writer::tag('div', $userimage, array('class'=>'image'));
 
                         $userlink = new moodle_url('/user/view.php', array('id'=>$user->id,'course'=>$choices->courseid));
-                        $name = html_writer::tag('a', fullname($user, $choices->fullnamecapability), array('href'=>$userlink, 'class'=>'username'));
+                        $name = html_writer::tag('a', $userfullname, array('href'=>$userlink, 'class'=>'username'));
                         $data .= html_writer::tag('div', $name, array('class'=>'fullname'));
                         $data .= html_writer::tag('div','', array('class'=>'clearfloat'));
                         $optionusers .= html_writer::tag('div', $data, array('class'=>'user'));
index 3040ef6..40fc894 100644 (file)
@@ -41,7 +41,7 @@ if (! $cm = get_coursemodule_from_instance('data', $data->id, $data->course)) {
 }
 
 if(! $course = $DB->get_record('course', array('id'=>$cm->course))) {
-    print_error('invalidcourseid', '', '', $cm->course);
+    print_error('invalidcourseid');
 }
 
 // fill in missing properties needed for updating of instance
index 812172a..7c504e5 100644 (file)
@@ -383,7 +383,7 @@ WHERE
  * @return string A unique message-id
  */
 function forum_get_email_message_id($postid, $usertoid, $hostname) {
-    return '<'.hash('sha256',$postid.'to'.$usertoid.'@'.$hostname).'>';
+    return '<'.hash('sha256',$postid.'to'.$usertoid).'@'.$hostname.'>';
 }
 
 /**
@@ -3177,6 +3177,14 @@ function forum_print_post($post, $discussion, $forum, &$cm, $course, $ownpost=fa
     $post->course = $course->id;
     $post->forum  = $forum->id;
     $post->message = file_rewrite_pluginfile_urls($post->message, 'pluginfile.php', $modcontext->id, 'mod_forum', 'post', $post->id);
+    if (!empty($CFG->enableplagiarism)) {
+        require_once($CFG->libdir.'/plagiarismlib.php');
+        $post->message .= plagiarism_get_links(array('userid' => $post->userid,
+            'content' => $post->message,
+            'cmid' => $cm->id,
+            'course' => $post->course,
+            'forum' => $post->forum));
+    }
 
     // caching
     if (!isset($cm->cache)) {
@@ -4022,6 +4030,16 @@ function forum_print_attachments($post, $cm, $type) {
                     $output .= '<br />';
                 }
             }
+
+            if (!empty($CFG->enableplagiarism)) {
+                require_once($CFG->libdir.'/plagiarismlib.php');
+                $output .= plagiarism_get_links(array('userid' => $post->userid,
+                    'file' => $file,
+                    'cmid' => $cm->id,
+                    'course' => $post->course,
+                    'forum' => $post->forum));
+                $output .= '<br />';
+            }
         }
     }
 
@@ -4279,6 +4297,9 @@ function forum_add_new_post($post, $mform, &$message) {
         forum_tp_mark_post_read($post->userid, $post, $post->forum);
     }
 
+    // Let Moodle know that assessable content is uploaded (eg for plagiarism detection)
+    forum_trigger_content_uploaded_event($post, $cm, 'forum_add_new_post');
+
     return $post->id;
 }
 
@@ -4325,6 +4346,9 @@ function forum_update_post($post, $mform, &$message) {
         forum_tp_mark_post_read($post->userid, $post, $post->forum);
     }
 
+    // Let Moodle know that assessable content is uploaded (eg for plagiarism detection)
+    forum_trigger_content_uploaded_event($post, $cm, 'forum_update_post');
+
     return true;
 }
 
@@ -4402,6 +4426,9 @@ function forum_add_discussion($discussion, $mform=null, &$message=null, $userid=
         forum_tp_mark_post_read($post->userid, $post, $post->forum);
     }
 
+    // Let Moodle know that assessable content is uploaded (eg for plagiarism detection)
+    forum_trigger_content_uploaded_event($post, $cm, 'forum_add_discussion');
+
     return $post->discussion;
 }
 
@@ -4524,6 +4551,33 @@ function forum_delete_post($post, $children, $course, $cm, $forum, $skipcompleti
     return false;
 }
 
+/**
+ * Sends post content to plagiarism plugin
+ * @param object $post Forum post object
+ * @param object $cm Course-module
+ * @param string $name
+ * @return bool
+*/
+function forum_trigger_content_uploaded_event($post, $cm, $name) {
+    $context = context_module::instance($cm->id);
+    $fs = get_file_storage();
+    $files = $fs->get_area_files($context->id, 'mod_forum', 'attachment', $post->id, "timemodified", false);
+    $eventdata = new stdClass();
+    $eventdata->modulename   = 'forum';
+    $eventdata->name         = $name;
+    $eventdata->cmid         = $cm->id;
+    $eventdata->itemid       = $post->id;
+    $eventdata->courseid     = $post->course;
+    $eventdata->userid       = $post->userid;
+    $eventdata->content      = $post->message;
+    if ($files) {
+        $eventdata->pathnamehashes = array_keys($files);
+    }
+    events_trigger('assessable_content_uploaded', $eventdata);
+
+    return true;
+}
+
 /**
  * @global object
  * @param object $post
index eb2d03c..ac62ec5 100644 (file)
@@ -139,6 +139,9 @@ class mod_forum_mod_form extends moodleform_mod {
         $mform->addHelpButton('warnafter', 'warnafter', 'forum');
         $mform->disabledIf('warnafter', 'blockperiod', 'eq', 0);
 
+        $coursecontext = context_course::instance($COURSE->id);
+        plagiarism_get_form_elements_module($mform, $coursecontext);
+
 //-------------------------------------------------------------------------------
 
         $this->standard_grading_coursemodule_elements();
index 20528d0..1162e6a 100644 (file)
@@ -877,6 +877,11 @@ if (!empty($parent)) {
 } else {
     if (!empty($forum->intro)) {
         echo $OUTPUT->box(format_module_intro('forum', $forum, $cm->id), 'generalbox', 'intro');
+
+        if (!empty($CFG->enableplagiarism)) {
+            require_once($CFG->libdir.'/plagiarismlib.php');
+            echo plagiarism_print_disclosure($cm->id);
+        }
     }
 }
 
index c1bec7f..89fa16a 100644 (file)
@@ -275,7 +275,7 @@ M.mod_quiz.secure_window = {
         }, '#secureclosebutton');
     },
 
-    close: function(url, delay) {
+    close: function(Y, url, delay) {
         setTimeout(function() {
             if (window.opener) {
                 window.opener.document.location.reload();
index 165ec10..820e711 100644 (file)
@@ -509,8 +509,8 @@ class mod_quiz_renderer extends plugin_renderer_base {
             $output .= html_writer::tag('p', get_string('pleaseclose', 'quiz'));
             $delay = 0;
         }
-        $this->page->requires->js_function_call('M.mod_quiz.secure_window.close',
-                array($url, $delay));
+        $this->page->requires->js_init_call('M.mod_quiz.secure_window.close',
+                array($url, $delay), false, quiz_get_js_module());
 
         $output .= $this->box_end();
         $output .= $this->footer();
@@ -1149,6 +1149,24 @@ class mod_quiz_renderer extends plugin_renderer_base {
                 'id' => $cm->id, 'mode' => quiz_report_default_report($context)));
         return html_writer::link($url, $summary);
     }
+
+    /**
+     * Output a graph, or a message saying that GD is required.
+     * @param moodle_url $url the URL of the graph.
+     * @param string $title the title to display above the graph.
+     * @return string HTML fragment for the graph.
+     */
+    public function graph(moodle_url $url, $title) {
+        global $CFG;
+
+        if (empty($CFG->gdversion)) {
+            $graph = get_string('gdneed');
+        } else {
+            $graph = html_writer::empty_tag('img', array('src' => $url, 'alt' => $title));
+        }
+
+        return $this->heading($title) . html_writer::tag('div', $graph, array('class' => 'graph'));
+    }
 }
 
 class mod_quiz_links_to_other_attempts implements renderable {
index ae2e1f6..27b4df5 100644 (file)
@@ -40,7 +40,7 @@ require_once($CFG->dirroot . '/mod/quiz/report/overview/overview_table.php');
 class quiz_overview_report extends quiz_attempts_report {
 
     public function display($quiz, $cm, $course) {
-        global $CFG, $DB, $OUTPUT;
+        global $CFG, $DB, $OUTPUT, $PAGE;
 
         list($currentgroup, $students, $groupstudents, $allowed) =
                 $this->init('overview', 'quiz_overview_settings_form', $quiz, $cm, $course);
@@ -237,30 +237,25 @@ class quiz_overview_report extends quiz_attempts_report {
         }
 
         if (!$table->is_downloading() && $options->usercanseegrades) {
+            $output = $PAGE->get_renderer('mod_quiz');
             if ($currentgroup && $groupstudents) {
                 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
                 $params[] = $quiz->id;
                 if ($DB->record_exists_select('quiz_grades', "userid $usql AND quiz = ?",
                         $params)) {
-                     $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
+                    $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
                             array('id' => $quiz->id, 'groupid' => $currentgroup));
-                     $graphname = get_string('overviewreportgraphgroup', 'quiz_overview',
+                    $graphname = get_string('overviewreportgraphgroup', 'quiz_overview',
                             groups_get_group_name($currentgroup));
-                     echo $OUTPUT->heading($graphname);
-                     echo html_writer::tag('div', html_writer::empty_tag('img',
-                            array('src' => $imageurl, 'alt' => $graphname)),
-                            array('class' => 'graph'));
+                    echo $output->graph($imageurl, $graphname);
                 }
             }
 
             if ($DB->record_exists('quiz_grades', array('quiz'=> $quiz->id))) {
-                 $graphname = get_string('overviewreportgraph', 'quiz_overview');
-                 $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
+                $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
                         array('id' => $quiz->id));
-                 echo $OUTPUT->heading($graphname);
-                 echo html_writer::tag('div', html_writer::empty_tag('img',
-                        array('src' => $imageurl, 'alt' => $graphname)),
-                        array('class' => 'graph'));
+                $graphname = get_string('overviewreportgraph', 'quiz_overview');
+                echo $output->graph($imageurl, $graphname);
             }
         }
         return true;
index 99cbd31..48c91ee 100644 (file)
@@ -579,18 +579,17 @@ class quiz_statistics_report extends quiz_default_report {
      * @param int $quizstatsid the id of the statistics to show in the graph.
      */
     protected function output_statistics_graph($quizstatsid, $s) {
-        global $OUTPUT;
+        global $PAGE;
 
         if ($s == 0) {
             return;
         }
 
+        $output = $PAGE->get_renderer('mod_quiz');
         $imageurl = new moodle_url('/mod/quiz/report/statistics/statistics_graph.php',
                 array('id' => $quizstatsid));
-        $OUTPUT->heading(get_string('statisticsreportgraph', 'quiz_statistics'));
-        echo html_writer::tag('div', html_writer::empty_tag('img', array('src' => $imageurl,
-                'alt' => get_string('statisticsreportgraph', 'quiz_statistics'))),
-                array('class' => 'graph'));
+        $graphname = get_string('statisticsreportgraph', 'quiz_statistics');
+        echo $output->graph($imageurl, $graphname);
     }
 
     /**
index aa9e48d..03f42f1 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$module->version   = 2012061700;       // The current module version (Date: YYYYMMDDXX).
+$module->version   = 2012061701;       // The current module version (Date: YYYYMMDDXX).
 $module->requires  = 2012061700;    // Requires this Moodle version.
 $module->component = 'mod_quiz';       // Full name of the plugin (used for diagnostics).
 $module->cron      = 60;
index fc31e9b..f671042 100644 (file)
@@ -110,7 +110,7 @@ class core_notes_external extends external_api {
             //check the course exists
             if (empty($courses[$note['courseid']])) {
                 $success = false;
-                $errormessage = get_string('invalidcourseid', 'notes', $note['courseid']);
+                $errormessage = get_string('invalidcourseid', 'error');
             } else {
                 // Ensure the current user is allowed to run this function
                 $context = get_context_instance(CONTEXT_COURSE, $note['courseid']);
index 8123771..9f9fcc6 100644 (file)
@@ -44,13 +44,13 @@ class plagiarism_plugin {
      * hook to allow plagiarism specific information to be returned unformatted
      * @param int $cmid
      * @param int $userid
-     * @param stored_file $file moodle file object
+     * @param $file file object
      * @return array containing at least:
      *   - 'analyzed' - whether the file has been successfully analyzed
      *   - 'score' - similarity score - ('' if not known)
      *   - 'reporturl' - url of originality report - '' if unavailable
      */
-    public function get_file_results($cmid, $userid, stored_file $file) {
+    public function get_file_results($cmid, $userid, $file) {
         return array('analyzed' => '', 'score' => '', 'reporturl' => '');
     }
     /**
index 0405ba5..a7b87d0 100644 (file)
@@ -108,7 +108,9 @@ class portfolio_plugin_googledocs extends portfolio_plugin_push_base {
         $mform->addElement('static', null, '', get_string('oauthinfo', 'portfolio_googledocs', $a));
 
         $mform->addElement('text', 'clientid', get_string('clientid', 'portfolio_googledocs'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'portfolio_googledocs'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
index cbef42c..fff8760 100644 (file)
@@ -108,7 +108,9 @@ class portfolio_plugin_picasa extends portfolio_plugin_push_base {
         $mform->addElement('static', null, '', get_string('oauthinfo', 'portfolio_picasa', $a));
 
         $mform->addElement('text', 'clientid', get_string('clientid', 'portfolio_picasa'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'portfolio_picasa'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
index 5dd1e86..9f1b67b 100644 (file)
@@ -68,8 +68,8 @@ class restore_qtype_shortanswer_plugin extends restore_qtype_plugin {
         $questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
 
         // If the question has been created by restore, we need to create its
-        // question_shortanswer too
-        if ($questioncreated) {
+        // question_shortanswer too, if they are defined (the gui should ensure this).
+        if ($questioncreated && !empty($data->answers)) {
             // Adjust some columns
             $data->question = $newquestionid;
             // Map sequence of question_answer ids
index d23f361..7c4e1f4 100644 (file)
@@ -1737,7 +1737,7 @@ M.core_filepicker.init = function(Y, options) {
                 setAttrs({id:'fp-tb-help-'+client_id+'-link', target:'_blank'}).
                 setStyle('display', 'none');
             toolbar.append(helplnk);
-            toolbar.one('.fp-tb-manage').one('a,button').
+            toolbar.one('.fp-tb-help').one('a,button').
                 on('click', function(e) {
                     e.preventDefault();
                     helplnk.simulate('click')
index ee56c02..c3a00e1 100644 (file)
@@ -119,7 +119,9 @@ class repository_googledocs extends repository {
 
         parent::type_config_form($mform);
         $mform->addElement('text', 'clientid', get_string('clientid', 'repository_googledocs'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'repository_googledocs'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
index 642c7b3..11f8eb0 100644 (file)
@@ -118,7 +118,9 @@ class repository_picasa extends repository {
 
         parent::type_config_form($mform);
         $mform->addElement('text', 'clientid', get_string('clientid', 'repository_picasa'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'repository_picasa'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
index 09dc4b2..d073270 100644 (file)
@@ -167,7 +167,7 @@ input.titleeditor {
 
 /* Course drag and drop upload styles */
 #dndupload-status {width:40%;margin:0 30%;padding:6px;border:1px solid #ddd;text-align:center;background:#ffc;position:absolute;z-index:9999;box-shadow:2px 2px 5px 1px #ccc;border-radius:0px 0px 8px 8px;z-index: 0;}
-.dndupload-preview {color:#909090;border:1px dashed #909090;}
+.dndupload-preview {color:#909090;border:1px dashed #909090;list-style:none;}
 .dndupload-progress-outer {width:70px;border:1px solid black;height:10px;display:inline-block;margin:0;padding:0;overflow:hidden;position:relative;}
 .dndupload-progress-inner {width:0%;height:100%;background-color:green;display:inline-block;margin:0;padding:0;float:left;}
 .dndupload-hidden {display:none;}
index 836233a..5fbacc3 100644 (file)
@@ -290,7 +290,7 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 /*.filemanager-container ul{margin:0;padding:0;}
 .filemanager-container ul li{white-space:nowrap;list-style-type:none;}
 .filemanager-container ul li a{padding:0}*/
-.filemanager .fp-content{overflow: auto;max-height: 472px;}
+.filemanager .fp-content{overflow: auto;max-height: 472px;min-height: 157px;}
 .filemanager-container, .filepicker-filelist {overflow:hidden;}
 
 /*
index bfa5476..9a497d2 100644 (file)
@@ -166,6 +166,22 @@ function user_get_users_by_id($userids) {
     return $DB->get_records_list('user', 'id', $userids);
 }
 
+/**
+ * Returns the list of default 'displayable' fields
+ *
+ * Contains database field names but also names used to generate information, such as enrolledcourses
+ *
+ * @return array of user fields
+ */
+function user_get_default_fields() {
+    return array( 'id', 'username', 'fullname', 'firstname', 'lastname', 'email',
+        'address', 'phone1', 'phone2', 'icq', 'skype', 'yahoo', 'aim', 'msn', 'department',
+        'institution', 'interests', 'firstaccess', 'lastaccess', 'auth', 'confirmed',
+        'idnumber', 'lang', 'theme', 'timezone', 'mailformat', 'description', 'descriptionformat',
+        'city', 'url', 'country', 'profileimageurlsmall', 'profileimageurl', 'customfields',
+        'groups', 'roles', 'preferences', 'enrolledcourses'
+    );
+}
 
 /**
  *
@@ -186,13 +202,7 @@ function user_get_user_details($user, $course = null, array $userfields = array(
     require_once($CFG->dirroot . "/user/profile/lib.php"); //custom field library
     require_once($CFG->dirroot . "/lib/filelib.php");      // file handling on description and friends
 
-    $defaultfields = array( 'id', 'username', 'fullname', 'firstname', 'lastname', 'email',
-        'address', 'phone1', 'phone2', 'icq', 'skype', 'yahoo', 'aim', 'msn', 'department',
-        'institution', 'interests', 'firstaccess', 'lastaccess', 'auth', 'confirmed',
-        'idnumber', 'lang', 'theme', 'timezone', 'mailformat', 'description', 'descriptionformat',
-        'city', 'url', 'country', 'profileimageurlsmall', 'profileimageurl', 'customfields',
-        'groups', 'roles', 'preferences', 'enrolledcourses'
-    );
+    $defaultfields = user_get_default_fields();
 
     if (empty($userfields)) {
         $userfields = $defaultfields;
index f1afca3..bf7c438 100644 (file)
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012071200.00;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012071700.00;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes