Merge branch 'MDL-28087_friendly_jabber' of git://github.com/andyjdavis/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Wed, 29 Jun 2011 18:11:17 +0000 (20:11 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Wed, 29 Jun 2011 18:11:17 +0000 (20:11 +0200)
59 files changed:
backup/moodle2/restore_stepslib.php
blog/lib.php
course/lib.php
course/report/completion/lang/en/coursereport_completion.php
course/report/completion/lib.php
course/report/lib.php [new file with mode: 0644]
course/report/log/lang/en/coursereport_log.php
course/report/log/lib.php
course/report/outline/index.php
course/report/outline/lang/en/coursereport_outline.php
course/report/outline/lib.php
course/report/participation/lang/en/coursereport_participation.php
course/report/participation/lib.php
course/report/progress/lang/en/coursereport_progress.php
course/report/progress/lib.php
course/report/stats/lang/en/coursereport_stats.php
course/report/stats/lib.php
lang/en/pagetype.php
lib/blocklib.php
lib/db/services.php
lib/questionlib.php
message/externallib.php
message/lib.php
mod/assignment/lib.php
mod/chat/lib.php
mod/choice/lib.php
mod/data/lib.php
mod/feedback/lib.php
mod/folder/lib.php
mod/forum/lib.php
mod/glossary/lib.php
mod/imscp/lib.php
mod/lesson/continue.php
mod/lesson/format.php
mod/lesson/import.php
mod/lesson/import_form.php
mod/lesson/lang/en/lesson.php
mod/lesson/lib.php
mod/lesson/locallib.php
mod/lesson/pagetypes/essay.php
mod/lesson/pagetypes/matching.php
mod/lesson/pagetypes/multichoice.php
mod/lesson/pagetypes/shortanswer.php
mod/lesson/pagetypes/truefalse.php
mod/lesson/styles.css
mod/lesson/view.php
mod/page/lib.php
mod/quiz/lib.php
mod/resource/lib.php
mod/scorm/lib.php
mod/survey/lib.php
mod/url/lib.php
mod/wiki/lib.php
mod/workshop/lib.php
notes/lib.php
tag/lib.php
user/externallib.php
user/lib.php
version.php

index 6178a04..ff5929c 100644 (file)
@@ -273,7 +273,9 @@ class restore_gradebook_structure_step extends restore_structure_step {
         //$this->set_mapping('grade_setting', $oldid, $newitemid);
     }
 
-    //put all activity grade items in the correct grade category and mark all for recalculation
+    /**
+     * put all activity grade items in the correct grade category and mark all for recalculation
+     */
     protected function after_execute() {
         global $DB;
 
@@ -284,8 +286,15 @@ class restore_gradebook_structure_step extends restore_structure_step {
         );
         $rs = $DB->get_recordset('backup_ids_temp', $conditions);
 
+        // We need this for calculation magic later on.
+        $mappings = array();
+
         if (!empty($rs)) {
             foreach($rs as $grade_item_backup) {
+
+                // Store the oldid with the new id.
+                $mappings[$grade_item_backup->itemid] = $grade_item_backup->newitemid;
+
                 $updateobj = new stdclass();
                 $updateobj->id = $grade_item_backup->newitemid;
 
@@ -301,6 +310,55 @@ class restore_gradebook_structure_step extends restore_structure_step {
         }
         $rs->close();
 
+        // We need to update the calculations for calculated grade items that may reference old
+        // grade item ids using ##gi\d+##.
+        list($sql, $params) = $DB->get_in_or_equal(array_values($mappings), SQL_PARAMS_NAMED);
+        $sql = "SELECT gi.id, gi.calculation
+                  FROM {grade_items} gi
+                 WHERE gi.id {$sql} AND
+                       calculation IS NOT NULL";
+        $rs = $DB->get_recordset_sql($sql, $params);
+        foreach ($rs as $gradeitem) {
+            // Collect all of the used grade item id references
+            if (preg_match_all('/##gi(\d+)##/', $gradeitem->calculation, $matches) < 1) {
+                // This calculation doesn't reference any other grade items... EASY!
+                continue;
+            }
+            // For this next bit we are going to do the replacement of id's in two steps:
+            // 1. We will replace all old id references with a special mapping reference.
+            // 2. We will replace all mapping references with id's
+            // Why do we do this?
+            // Because there potentially there will be an overlap of ids within the query and we
+            // we substitute the wrong id.. safest way around this is the two step system
+            $calculationmap = array();
+            $mapcount = 0;
+            foreach ($matches[1] as $match) {
+                // Check that the old id is known to us, if not it was broken to begin with and will
+                // continue to be broken.
+                if (!array_key_exists($match, $mappings)) {
+                    continue;
+                }
+                // Our special mapping key
+                $mapping = '##MAPPING'.$mapcount.'##';
+                // The old id that exists within the calculation now
+                $oldid = '##gi'.$match.'##';
+                // The new id that we want to replace the old one with.
+                $newid = '##gi'.$mappings[$match].'##';
+                // Replace in the special mapping key
+                $gradeitem->calculation = str_replace($oldid, $mapping, $gradeitem->calculation);
+                // And record the mapping
+                $calculationmap[$mapping] = $newid;
+                $mapcount++;
+            }
+            // Iterate all special mappings for this calculation and replace in the new id's
+            foreach ($calculationmap as $mapping => $newid) {
+                $gradeitem->calculation = str_replace($mapping, $newid, $gradeitem->calculation);
+            }
+            // Update the calculation now that its being remapped
+            $DB->update_record('grade_items', $gradeitem);
+        }
+        $rs->close();
+
         //need to correct the grade category path and parent
         $conditions = array(
             'courseid' => $this->get_courseid()
@@ -1800,28 +1858,47 @@ class restore_activity_grades_structure_step extends restore_structure_step {
     }
 
     protected function process_grade_item($data) {
+        global $DB;
 
         $data = (object)($data);
         $oldid       = $data->id;        // We'll need these later
         $oldparentid = $data->categoryid;
+        $courseid = $this->get_courseid();
 
         // make sure top course category exists, all grade items will be associated
         // to it. Later, if restoring the whole gradebook, categories will be introduced
-        $coursecat = grade_category::fetch_course_category($this->get_courseid());
+        $coursecat = grade_category::fetch_course_category($courseid);
         $coursecatid = $coursecat->id; // Get the categoryid to be used
 
+        $idnumber = null;
+        if (!empty($data->idnumber)) {
+            // Don't get any idnumber from course module. Keep them as they are in grade_item->idnumber
+            // Reason: it's not clear what happens with outcomes->idnumber or activities with multiple items (workshop)
+            // so the best is to keep the ones already in the gradebook
+            // Potential problem: duplicates if same items are restored more than once. :-(
+            // This needs to be fixed in some way (outcomes & activities with multiple items)
+            // $data->idnumber     = get_coursemodule_from_instance($data->itemmodule, $data->iteminstance)->idnumber;
+            // In any case, verify always for uniqueness
+            $sql = "SELECT cm.id
+                      FROM {course_modules} cm
+                     WHERE cm.course = :courseid AND
+                           cm.idnumber = :idnumber AND
+                           cm.id <> :cmid";
+            $params = array(
+                'courseid' => $courseid,
+                'idnumber' => $data->idnumber,
+                'cmid' => $this->task->get_moduleid()
+            );
+            if (!$DB->record_exists_sql($sql, $params) && !$DB->record_exists('grade_items', array('courseid' => $courseid, 'idnumber' => $data->idnumber))) {
+                $idnumber = $data->idnumber;
+            }
+        }
+
         unset($data->id);
         $data->categoryid   = $coursecatid;
         $data->courseid     = $this->get_courseid();
         $data->iteminstance = $this->task->get_activityid();
-        // Don't get any idnumber from course module. Keep them as they are in grade_item->idnumber
-        // Reason: it's not clear what happens with outcomes->idnumber or activities with multiple items (workshop)
-        // so the best is to keep the ones already in the gradebook
-        // Potential problem: duplicates if same items are restored more than once. :-(
-        // This needs to be fixed in some way (outcomes & activities with multiple items)
-        // $data->idnumber     = get_coursemodule_from_instance($data->itemmodule, $data->iteminstance)->idnumber;
-        // In any case, verify always for uniqueness
-        $data->idnumber = grade_verify_idnumber($data->idnumber, $this->get_courseid()) ? $data->idnumber : null;
+        $data->idnumber     = $idnumber;
         $data->scaleid      = $this->get_mappingid('scale', $data->scaleid);
         $data->outcomeid    = $this->get_mappingid('outcome', $data->outcomeid);
         $data->timecreated  = $this->apply_date_offset($data->timecreated);
index 0f25fb4..c37af10 100644 (file)
@@ -1035,7 +1035,7 @@ function blog_comment_validate($comment_param) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function blog_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function blog_page_type_list($pagetype, $parentcontext, $currentcontext) {
     return array(
         '*'=>get_string('page-x', 'pagetype'),
         'blog-*'=>get_string('page-blog-x', 'blog'),
index 1a9dbd9..8517148 100644 (file)
@@ -4218,7 +4218,7 @@ class course_request {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function course_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function course_page_type_list($pagetype, $parentcontext, $currentcontext) {
     // if above course context ,display all course fomats
     list($currentcontext, $course, $cm) = get_context_info_array($currentcontext->id);
     if ($course->id == SITEID) {
@@ -4230,4 +4230,4 @@ function course_pagetypelist($pagetype, $parentcontext, $currentcontext) {
             'mod-*'=>get_string('page-mod-x', 'pagetype')
         );
     }
-}
+}
\ No newline at end of file
index 3e67898..2ec123a 100644 (file)
@@ -2,4 +2,5 @@
 
 $string['completion:view'] = 'View course completion report';
 $string['completiondate']='Completion date';
+$string['pluginpagetype'] = 'Completion course report';
 $string['pluginname']='Course completion';
index a84f3a2..7bf087e 100644 (file)
@@ -44,3 +44,18 @@ function completion_report_extend_navigation($navigation, $course, $context) {
         }
     }
 }
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function completion_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-completion-*' => get_string('pluginpagetype',  'coursereport_completion')
+    );
+    return $array;
+}
diff --git a/course/report/lib.php b/course/report/lib.php
new file mode 100644 (file)
index 0000000..3ed43f7
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains functions used by course reports
+ *
+ * @since 2.1
+ * @package course-report
+ * @copyright 2011 Andrew Davis
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function coursereport_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype')
+    );
+    return $array;
+}
\ No newline at end of file
index dc37408..431e260 100644 (file)
@@ -27,4 +27,5 @@ $string['loglive'] = 'Live logs';
 $string['log:view'] = 'View course logs';
 $string['log:viewlive'] = 'View live logs';
 $string['log:viewtoday'] = 'View today\'s logs';
+$string['pluginpagetype'] = 'Log course report';
 $string['pluginname'] = 'Logs';
index 96cbdc7..de27692 100644 (file)
@@ -537,3 +537,18 @@ function log_report_extend_navigation($navigation, $course, $context) {
         $navigation->add(get_string('pluginname', 'coursereport_log'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
     }
 }
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function log_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-log-*' => get_string('pluginpagetype',  'coursereport_log')
+    );
+    return $array;
+}
\ No newline at end of file
index ad4ef64..dc1dd10 100644 (file)
             $reportrow->cells[] = $numviewscell;
 
             if ($CFG->useblogassociations) {
+                require_once($CFG->dirroot.'/blog/lib.php');
                 $blogcell = new html_table_cell();
                 $blogcell->attributes['class'] = 'blog';
                 if ($blogcount = blog_get_associated_count($course->id, $cm->id)) {
index eaf1886..6bce7b8 100644 (file)
@@ -24,4 +24,5 @@
  */
 
 $string['outline:view'] = 'View course activity report';
+$string['pluginpagetype'] = 'Course activity report';
 $string['pluginname'] = 'Course activity';
index c020dcc..f3632b3 100644 (file)
@@ -37,4 +37,19 @@ function outline_report_extend_navigation($navigation, $course, $context) {
         $url = new moodle_url('/course/report/outline/index.php', array('id'=>$course->id));
         $navigation->add(get_string( 'activityreport' ), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
     }
+}
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function outline_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-outline-*' => get_string('pluginpagetype',  'coursereport_outline')
+    );
+    return $array;
 }
\ No newline at end of file
index 82e9864..16e5eaa 100644 (file)
@@ -24,4 +24,5 @@
  */
 
 $string['participation:view'] = 'View course participation report';
+$string['pluginpagetype'] = 'Participation course report';
 $string['pluginname'] = 'Course participation';
index 7071876..62429c9 100644 (file)
@@ -37,4 +37,19 @@ function participation_report_extend_navigation($navigation, $course, $context)
         $url = new moodle_url('/course/report/participation/index.php', array('id'=>$course->id));
         $navigation->add(get_string('participationreport'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
     }
+}
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function participation_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-participation-*' => get_string('pluginpagetype',  'coursereport_participation')
+    );
+    return $array;
 }
\ No newline at end of file
index 7cb9005..dd27c66 100644 (file)
@@ -24,4 +24,5 @@
  */
 
 $string['pluginname'] = 'Activity completion';
+$string['pluginpagetype'] = 'Progress course report';
 $string['progress:view'] = 'View activity completion reports';
index f4c74f6..23a9686 100644 (file)
@@ -49,3 +49,18 @@ function progress_report_extend_navigation($navigation, $course, $context) {
         $navigation->add(get_string('pluginname','coursereport_progress'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
     }
 }
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function progress_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-progress-*' => get_string('pluginpagetype',  'coursereport_progress')
+    );
+    return $array;
+}
\ No newline at end of file
index d4491a9..38815c8 100644 (file)
@@ -24,4 +24,5 @@
  */
 
 $string['pluginname'] = 'Course statistics';
+$string['pluginpagetype'] = 'Statistics course report';
 $string['stats:view'] = 'View course statistics report';
index ed31e78..220e8df 100644 (file)
@@ -91,3 +91,18 @@ function stats_report_extend_navigation($navigation, $course, $context) {
         }
     }
 }
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function stats_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-stats-*' => get_string('pluginpagetype',  'coursereport_stats')
+    );
+    return $array;
+}
\ No newline at end of file
index bc540f0..7a073f4 100644 (file)
@@ -25,6 +25,7 @@
 
 $string['page-course-view-x'] = 'Any type of course main page';
 $string['page-course-x'] = 'Any course page';
+$string['page-course-report-x'] = 'Any course report';
 $string['page-mod-x'] = 'Any activity module page';
 $string['page-mod-x-view'] = 'Any main activity module page';
 $string['page-my-index'] = 'My home page';
index 608a3d5..991b34d 100644 (file)
@@ -1217,13 +1217,14 @@ class block_manager {
                 // If the block wants to be system-wide, then explicitly set that
                 if ($data->bui_contexts == BUI_CONTEXTS_ENTIRE_SITE) {   // Only possible on a frontpage or system page
                     $bi->parentcontextid = $systemcontext->id;
-                    $bi->showinsubcontexts = 1;
+                    $bi->showinsubcontexts = BUI_CONTEXTS_CURRENT_SUBS; //show in current and sub contexts
+                    $bi->pagetypepattern = '*';
 
                 } else { // The block doesn't want to be system-wide, so let's ensure that
                     if ($parentcontext->id == $systemcontext->id) {  // We need to move it to the front page
                         $frontpagecontext = get_context_instance(CONTEXT_COURSE, SITEID);
                         $bi->parentcontextid = $frontpagecontext->id;
-                        $bi->pagetypepattern = '*';  // Just in case
+                        $bi->pagetypepattern = 'site-index';
                     }
                 }
             }
@@ -1563,34 +1564,72 @@ function generate_page_type_patterns($pagetype, $parentcontext = null, $currentc
 
     $bits = explode('-', $pagetype);
 
-    $component = clean_param(reset($bits), PARAM_ALPHANUMEXT);
-    $function = 'default_pagetypelist';
-
     $core = get_core_subsystems();
     $plugins = get_plugin_types();
 
-    // First check to see if the initial component is a core component
-    // if its not check to see if it is a plugin component.
-    if (array_key_exists($component, $core) && !empty($core[$component])) {
-        $libfile = $CFG->dirroot.'/'.$core[$component].'/lib.php';
-        if (file_exists($libfile)) {
-            require_once($libfile);
-            if (function_exists($component.'_pagetypelist')) {
-                $function = $component.'_pagetypelist';
+    //progressively strip pieces off the page type looking for a match
+    $componentarray = null;
+    for ($i = count($bits); $i > 0; $i--) {
+        $possiblecomponentarray = array_slice($bits, 0, $i);
+        $possiblecomponent = implode('', $possiblecomponentarray);
+
+        // Check to see if the component is a core component
+        if (array_key_exists($possiblecomponent, $core) && !empty($core[$possiblecomponent])) {
+            $libfile = $CFG->dirroot.'/'.$core[$possiblecomponent].'/lib.php';
+            if (file_exists($libfile)) {
+                require_once($libfile);
+                $function = $possiblecomponent.'_page_type_list';
+                if (function_exists($function)) {
+                    if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) {
+                        break;
+                    }
+                }
             }
         }
-    } else if (array_key_exists($component, $plugins) && !empty($plugins[$component])) {
-        $function = 'plugin_pagetypelist';
-        if (function_exists($component.'_pagetypelist')) {
-            $function = $component.'_pagetypelist';
+
+        //check the plugin directory and look for a callback
+        if (array_key_exists($possiblecomponent, $plugins) && !empty($plugins[$possiblecomponent])) {
+
+            //We've found a plugin type. Look for a plugin name by getting the next section of page type
+            if (count($bits) > $i) {
+                $pluginname = $bits[$i];
+                $directory = get_plugin_directory($possiblecomponent, $pluginname);
+                if (!empty($directory)){
+                    $libfile = $directory.'/lib.php';
+                    if (file_exists($libfile)) {
+                        require_once($libfile);
+                        $function = $pluginname.'_page_type_list';
+                        if (function_exists($function)) {
+                            if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
+            //we'll only get to here if we still don't have any patterns
+            //the plugin type may have a callback
+            $directory = get_plugin_directory($possiblecomponent, null);
+            if (!empty($directory)){
+                $libfile = $directory.'/lib.php';
+                if (file_exists($libfile)) {
+                    require_once($libfile);
+                    $function = $possiblecomponent.'_page_type_list';
+                    if (function_exists($function)) {
+                        if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) {
+                            break;
+                        }
+                    }
+                }
+            }
         }
     }
-    // Call the most appropriate function we could determine
-    $patterns = $function($pagetype, $parentcontext, $currentcontext);
+
     if (empty($patterns)) {
-        // If there are no patterns default to just the current pattern.
-        $patterns = array($pagetype => $pagetype);
+        $patterns = default_page_type_list($pagetype, $parentcontext, $currentcontext);
     }
+
     return $patterns;
 }
 
@@ -1602,7 +1641,7 @@ function generate_page_type_patterns($pagetype, $parentcontext = null, $currentc
  * @param stdClass $currentcontext
  * @return array
  */
-function default_pagetypelist($pagetype, $parentcontext = null, $currentcontext = null) {
+function default_page_type_list($pagetype, $parentcontext = null, $currentcontext = null) {
     // Generate page type patterns based on current page type if
     // callbacks haven't been defined
     $patterns = array($pagetype => $pagetype);
@@ -1622,40 +1661,6 @@ function default_pagetypelist($pagetype, $parentcontext = null, $currentcontext
     return $patterns;
 }
 
-/**
- * Generates a page type list for plugins
- *
- * @param string $pagetype
- * @param stdClass $parentcontext
- * @param stdClass $currentcontext
- * @return array
- */
-function plugin_pagetypelist($pagetype, $parentcontext = null, $currentcontext = null) {
-    global $CFG;
-
-    // for modules
-    $bits = explode('-', $pagetype);
-    $plugintype = $bits[0];
-    $pluginname = $bits[1];
-    $directory = get_plugin_directory($plugintype, $pluginname);
-    if (empty($directory)) {
-        return array();
-    }
-    $libfile = $directory.'/lib.php';
-    require_once($libfile);
-    $function = $pluginname.'_pagetypelist';
-    if (!function_exists($function)) {
-        return array();
-    }
-    $patterns = $function($pagetype, $parentcontext, $currentcontext);
-    if ($parentcontext->contextlevel == CONTEXT_COURSE) {
-        // including course page type
-        require_once("$CFG->dirroot/course/lib.php");
-        $patterns = array_merge(course_pagetypelist($pagetype, $parentcontext, $currentcontext), $patterns);
-    }
-    return $patterns;
-}
-
 /**
  * Generates the page type list for the my moodle page
  *
@@ -1664,7 +1669,7 @@ function plugin_pagetypelist($pagetype, $parentcontext = null, $currentcontext =
  * @param stdClass $currentcontext
  * @return array
  */
-function my_pagetypelist($pagetype, $parentcontext = null, $currentcontext = null) {
+function my_page_type_list($pagetype, $parentcontext = null, $currentcontext = null) {
     return array('my-index' => 'my-index');
 }
 
@@ -1677,8 +1682,8 @@ function my_pagetypelist($pagetype, $parentcontext = null, $currentcontext = nul
  * @param stdClass $currentcontext
  * @return array
  */
-function mod_pagetypelist($pagetype, $parentcontext = null, $currentcontext = null) {
-    $patterns = plugin_pagetypelist($pagetype, $parentcontext, $currentcontext);
+function mod_page_type_list($pagetype, $parentcontext = null, $currentcontext = null) {
+    $patterns = plugin_page_type_list($pagetype, $parentcontext, $currentcontext);
     if (empty($patterns)) {
         // if modules don't have callbacks
         // generate two default page type patterns for modules only
index 53c1309..117bf9d 100644 (file)
@@ -129,6 +129,15 @@ $functions = array(
         'capabilities'=> 'moodle/user:viewdetails, moodle/user:viewhiddendetails, moodle/course:useremail, moodle/user:update',
     ),
 
+    'moodle_user_get_users_by_courseid' => array(
+        'classname'   => 'moodle_user_external',
+        'methodname'  => 'get_users_by_courseid',
+        'classpath'   => 'user/externallib.php',
+        'description' => 'Get enrolled users by course id.',
+        'type'        => 'read',
+        'capabilities'=> 'moodle/user:viewdetails, moodle/user:viewhiddendetails, moodle/course:useremail, moodle/user:update, moodle/site:accessallgroups',
+    ),
+
     'moodle_user_get_course_participants_by_id' => array(
         'classname'   => 'moodle_user_external',
         'methodname'  => 'get_course_participants_by_id',
@@ -217,11 +226,11 @@ $functions = array(
 
     // === message related functions ===
 
-    'moodle_message_send_messages' => array(
+    'moodle_message_send_instantmessages' => array(
         'classname'   => 'moodle_message_external',
-        'methodname'  => 'send_messages',
+        'methodname'  => 'send_instantmessages',
         'classpath'   => 'message/externallib.php',
-        'description' => 'Send messages',
+        'description' => 'Send instant messages',
         'type'        => 'write',
         'capabilities'=> 'moodle/site:sendmessage',
     ),
@@ -258,7 +267,8 @@ $services = array(
             'moodle_webservice_get_siteinfo',
             'moodle_notes_create_notes',
             'moodle_user_get_course_participants_by_id',
-            'moodle_message_send_messages'),
+            'moodle_user_get_users_by_courseid',
+            'moodle_message_send_instantmessages'),
         'enabled' => 0,
         'restrictedusers' => 0,
         'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE
index 5c7d89f..671dbe6 100644 (file)
@@ -1826,7 +1826,7 @@ function question_make_export_url($contextid, $categoryid, $format, $withcategor
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function question_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function question_page_type_list($pagetype, $parentcontext, $currentcontext) {
     global $CFG;
     $types = array(
         'question-*'=>get_string('page-question-x', 'question'),
@@ -1837,7 +1837,7 @@ function question_pagetypelist($pagetype, $parentcontext, $currentcontext) {
     );
     if ($currentcontext->contextlevel == CONTEXT_COURSE) {
         require_once($CFG->dirroot . '/course/lib.php');
-        return array_merge(course_pagetypelist($pagetype, $parentcontext, $currentcontext), $types);
+        return array_merge(course_page_type_list($pagetype, $parentcontext, $currentcontext), $types);
     } else {
         return $types;
     }
index 00f24a8..1a7a160 100644 (file)
@@ -31,7 +31,7 @@ class moodle_message_external extends external_api {
      * Returns description of method parameters
      * @return external_function_parameters
      */
-    public static function send_messages_parameters() {
+    public static function send_instantmessages_parameters() {
         return new external_function_parameters(
             array(
                 'messages' => new external_multiple_structure(
@@ -53,7 +53,7 @@ class moodle_message_external extends external_api {
      * @param $messages  An array of message to send.
      * @return boolean
      */
-    public static function send_messages($messages = array()) {
+    public static function send_instantmessages($messages = array()) {
         global $CFG, $USER, $DB;
         require_once($CFG->dirroot . "/message/lib.php");
 
@@ -67,24 +67,32 @@ class moodle_message_external extends external_api {
         self::validate_context($context);
         require_capability('moodle/site:sendmessage', $context);
 
-        $params = self::validate_parameters(self::send_messages_parameters(), array('messages' => $messages));
+        $params = self::validate_parameters(self::send_instantmessages_parameters(), array('messages' => $messages));
 
         //retrieve all tousers of the messages
-        $touserids = array();
+        $receivers = array();
         foreach($params['messages'] as $message) {
-            $touserids[] = $message['touserid'];
+            $receivers[] = $message['touserid'];
         }
-        list($sqluserids, $sqlparams) = $DB->get_in_or_equal($touserids, SQL_PARAMS_NAMED, 'userid_');
+        list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers, SQL_PARAMS_NAMED, 'userid_');
         $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
-
-        //retrieve the tousers who are blocking the $USER
+        $blocklist   = array();
+        $contactlist = array();
         $sqlparams['contactid'] = $USER->id;
-        $sqlparams['blocked'] = 1;
-        //Note: return userid field should be unique for the below request,
-        //so we'll use this field as key of $blockingcontacts
-        $blockingcontacts = $DB->get_records_select("message_contacts",
-                "userid " . $sqluserids . " AND contactid = :contactid AND blocked = :blocked",
-                $sqlparams, '', "userid");
+        $rs = $DB->get_recordset_sql("SELECT *
+                                        FROM {message_contacts}
+                                       WHERE userid $sqluserids
+                                             AND contactid = :contactid", $sqlparams);
+        foreach ($rs as $record) {
+            if ($record->blocked) {
+                // $record->userid is blocking current user
+                $blocklist[$record->userid] = true;
+            } else {
+                // $record->userid have current user as contact
+                $contactlist[$record->userid] = true;
+            }
+        }
+        $rs->close();
 
         $canreadallmessages = has_capability('moodle/site:readallmessages', $context);
 
@@ -104,14 +112,16 @@ class moodle_message_external extends external_api {
             }
 
             //check that the touser is not blocking the current user
-            if ($success and isset($blockingcontacts[$message['touserid']]) and !$canreadallmessages) {
+            if ($success and !empty($blocklist[$message['touserid']]) and !$canreadallmessages) {
                 $success = false;
                 $errormessage = get_string('userisblockingyou', 'message');
             }
 
             // Check if the user is a contact
             //TODO: performance improvement - edit the function so we can pass an array instead userid
-            if ($success && empty($contact) && get_user_preferences('message_blocknoncontacts', NULL, $message['touserid']) == null) {
+            $blocknoncontacts = get_user_preferences('message_blocknoncontacts', NULL, $message['touserid']);
+            // message_blocknoncontacts option is on and current user is not in contact list
+            if ($success && empty($contactlist[$message['touserid']]) && !empty($blocknoncontacts)) {
                 // The user isn't a contact and they have selected to block non contacts so this message won't be sent.
                 $success = false;
                 $errormessage = get_string('userisblockingyounoncontact', 'message');
@@ -144,12 +154,12 @@ class moodle_message_external extends external_api {
      * Returns description of method result value
      * @return external_description
      */
-    public static function send_messages_returns() {
+    public static function send_instantmessages_returns() {
         return new external_multiple_structure(
             new external_single_structure(
                 array(
-                    'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
                     'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds:  id of the created message if it succeeded, -1 when failed'),
+                    'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
                     'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL)
                 )
             )
index 8020453..9de50e0 100644 (file)
@@ -2369,6 +2369,6 @@ function translate_message_default_setting($plugindefault, $processorname) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function message_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function message_page_type_list($pagetype, $parentcontext, $currentcontext) {
     return array('messages-*'=>get_string('page-message-x', 'message'));
 }
index 73a50f0..84665f8 100644 (file)
@@ -3723,7 +3723,7 @@ function assignment_get_file_areas($course, $cm, $context) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function assignment_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function assignment_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array(
         'mod-assignment-*'=>get_string('page-mod-assignment-x', 'assignment'),
         'mod-assignment-view'=>get_string('page-mod-assignment-view', 'assignment'),
index c40b833..a59a5e2 100644 (file)
@@ -1312,7 +1312,7 @@ function chat_user_logout($user) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function chat_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function chat_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-chat-*'=>get_string('page-mod-chat-x', 'chat'));
     return $module_pagetype;
 }
index b9b1fa0..a03db26 100644 (file)
@@ -863,7 +863,7 @@ function choice_get_completion_state($course, $cm, $userid, $type) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function choice_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function choice_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-choice-*'=>get_string('page-mod-choice-x', 'choice'));
     return $module_pagetype;
 }
index ff954dd..8758bfc 100644 (file)
@@ -3344,7 +3344,7 @@ function data_comment_validate($comment_param) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function data_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function data_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-data-*'=>get_string('page-mod-data-x', 'data'));
     return $module_pagetype;
 }
index b777e7e..59f574f 100644 (file)
@@ -2788,7 +2788,7 @@ function feedback_init_feedback_session() {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function feedback_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function feedback_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-feedback-*'=>get_string('page-mod-feedback-x', 'feedback'));
     return $module_pagetype;
 }
index 20775d5..491e5ed 100644 (file)
@@ -343,7 +343,7 @@ function folder_extend_navigation($navigation, $course, $module, $cm) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function folder_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function folder_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-folder-*'=>get_string('page-mod-folder-x', 'folder'));
     return $module_pagetype;
 }
index 03ad341..208e008 100644 (file)
@@ -7964,7 +7964,7 @@ function forum_cm_info_view(cm_info $cm) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function forum_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function forum_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $forum_pagetype = array(
         'mod-forum-*'=>get_string('page-mod-forum-x', 'forum'),
         'mod-forum-view'=>get_string('page-mod-forum-view', 'forum'),
index d488752..8df1014 100644 (file)
@@ -2861,7 +2861,7 @@ function glossary_comment_validate($comment_param) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function glossary_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function glossary_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-glossary-*'=>get_string('page-mod-glossary-x', 'glossary'));
     return $module_pagetype;
 }
index 697c293..af804cf 100644 (file)
@@ -407,7 +407,7 @@ function imscp_extend_navigation($navigation, $course, $module, $cm) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function imscp_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function imscp_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-imscp-*'=>get_string('page-mod-imscp-x', 'imscp'));
     return $module_pagetype;
 }
index d207aae..384cb47 100644 (file)
@@ -67,6 +67,13 @@ if (!$canmanage) {
 
 // record answer (if necessary) and show response (if none say if answer is correct or not)
 $page = $lesson->load_page(required_param('pageid', PARAM_INT));
+
+$userhasgrade = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
+$reviewmode = false;
+if ($userhasgrade && !$lesson->retake) {
+    $reviewmode = true;
+}
+
 // Check the page has answers [MDL-25632]
 if (count($page->answers) > 0) {
     $result = $page->record_attempt($context);
@@ -80,7 +87,7 @@ if (count($page->answers) > 0) {
 
 if (isset($USER->modattempts[$lesson->id])) {
     // make sure if the student is reviewing, that he/she sees the same pages/page path that he/she saw the first time
-    if ($USER->modattempts[$lesson->id] == $page->id && $page->nextpageid == 0) {  // remember, this session variable holds the pageid of the last page that the user saw
+    if ($USER->modattempts[$lesson->id]->pageid == $page->id && $page->nextpageid == 0) {  // remember, this session variable holds the pageid of the last page that the user saw
         $result->newpageid = LESSON_EOL;
     } else {
         $nretakes = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
@@ -153,11 +160,11 @@ if ($canmanage) {
     }
 }
 // Report attempts remaining
-if ($result->attemptsremaining != 0 && !$lesson->review) {
+if ($result->attemptsremaining != 0 && !$lesson->review && !$reviewmode) {
     $lesson->add_message(get_string('attemptsremaining', 'lesson', $result->attemptsremaining));
 }
 // Report if max attempts reached
-if ($result->maxattemptsreached != 0 && !$lesson->review) {
+if ($result->maxattemptsreached != 0 && !$lesson->review && !$reviewmode) {
     $lesson->add_message('('.get_string("maximumnumberofattemptsreached", "lesson").')');
 }
 
@@ -172,7 +179,7 @@ if ($lesson->displayleft) {
     echo '<a name="maincontent" id="maincontent" title="'.get_string('anchortitle', 'lesson').'"></a>';
 }
 // This calculates and prints the ongoing score message
-if ($lesson->ongoing) {
+if ($lesson->ongoing && !$reviewmode) {
     echo $lessonoutput->ongoing_score($lesson);
 }
 echo $result->feedback;
@@ -180,17 +187,17 @@ echo $result->feedback;
 // User is modifying attempts - save button and some instructions
 if (isset($USER->modattempts[$lesson->id])) {
     $url = $CFG->wwwroot.'/mod/lesson/view.php';
-    $content = $OUTPUT->box(get_string("savechangesandeol", "lesson"), 'center');
+    $content = $OUTPUT->box(get_string("gotoendoflesson", "lesson"), 'center');
     $content .= $OUTPUT->box(get_string("or", "lesson"), 'center');
-    $content .= $OUTPUT->box(get_string("continuetoanswer", "lesson"), 'center');
+    $content .= $OUTPUT->box(get_string("continuetonextpage", "lesson"), 'center');
     $content .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'id', 'value'=>$cm->id));
     $content .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'pageid', 'value'=>LESSON_EOL));
-    $content .= html_writer::empty_tag('input', array('type'=>'submit', 'name'=>'submit', 'value'=>get_string('savechanges', 'lesson')));
+    $content .= html_writer::empty_tag('input', array('type'=>'submit', 'name'=>'submit', 'value'=>get_string('finish', 'lesson')));
     echo html_writer::tag('form', "<div>$content</div>", array('method'=>'post', 'action'=>$url));
 }
 
 // Review button back
-if ($lesson->review && !$result->correctanswer && !$result->noanswer && !$result->isessayquestion) {
+if (!$result->correctanswer && !$result->noanswer && !$result->isessayquestion && !$reviewmode) {
     $url = $CFG->wwwroot.'/mod/lesson/view.php';
     $content = html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'id', 'value'=>$cm->id));
     $content .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'pageid', 'value'=>$page->id));
index 6f131ad..11fbd4a 100644 (file)
@@ -97,7 +97,8 @@ function lesson_save_question_options($question, $lesson) {
                     $answer->timecreated   = $timenow;
                     $answer->grade = $question->fraction[$key] * 100;
                     $answer->answer   = $dataanswer;
-                    $answer->response = $question->feedback[$key];
+                    $answer->response = $question->feedback[$key]['text'];
+                    $answer->responseformat = $question->feedback[$key]['format'];
                     $answer->id = $DB->insert_record("lesson_answers", $answer);
                     $answers[] = $answer->id;
                     if ($question->fraction[$key] > $maxfraction) {
@@ -134,7 +135,8 @@ function lesson_save_question_options($question, $lesson) {
                     $max = $question->answer[$key] + $question->tolerance[$key];
                     $answer->answer   = $min.":".$max;
                     // $answer->answer   = $question->min[$key].":".$question->max[$key]; original line for min/max
-                    $answer->response = $question->feedback[$key];
+                    $answer->response = $question->feedback[$key]['text'];
+                    $answer->responseformat = $question->feedback[$key]['format'];
                     $answer->id = $DB->insert_record("lesson_answers", $answer);
 
                     $answers[] = $answer->id;
@@ -160,12 +162,13 @@ function lesson_save_question_options($question, $lesson) {
             $answer->pageid = $question->id;
             $answer->timecreated   = $timenow;
             $answer->answer = get_string("true", "quiz");
-            $answer->grade = $question->answer * 100;
+            $answer->grade = $question->correctanswer * 100;
             if ($answer->grade > 50 ) {
                 $answer->jumpto = LESSON_NEXTPAGE;
             }
             if (isset($question->feedbacktrue)) {
-                $answer->response = $question->feedbacktrue;
+                $answer->response = $question->feedbacktrue['text'];
+                $answer->responseformat = $question->feedbacktrue['format'];
             }
             $DB->insert_record("lesson_answers", $answer);
 
@@ -175,12 +178,13 @@ function lesson_save_question_options($question, $lesson) {
             $answer->pageid = $question->id;
             $answer->timecreated   = $timenow;
             $answer->answer = get_string("false", "quiz");
-            $answer->grade = (1 - (int)$question->answer) * 100;
+            $answer->grade = (1 - (int)$question->correctanswer) * 100;
             if ($answer->grade > 50 ) {
                 $answer->jumpto = LESSON_NEXTPAGE;
             }
             if (isset($question->feedbackfalse)) {
-                $answer->response = $question->feedbackfalse;
+                $answer->response = $question->feedbackfalse['text'];
+                $answer->responseformat = $question->feedbackfalse['format'];
             }
             $DB->insert_record("lesson_answers", $answer);
 
@@ -212,8 +216,10 @@ function lesson_save_question_options($question, $lesson) {
                         $answer->score = 1;
                     }
                     // end Replace
-                    $answer->answer   = $dataanswer;
-                    $answer->response = $question->feedback[$key];
+                    $answer->answer   = $dataanswer['text'];
+                    $answer->answerformat   = $dataanswer['format'];
+                    $answer->response = $question->feedback[$key]['text'];
+                    $answer->responseformat = $question->feedback[$key]['format'];
                     $answer->id = $DB->insert_record("lesson_answers", $answer);
                     // for Sanity checks
                     if ($question->fraction[$key] > 0) {
@@ -268,7 +274,8 @@ function lesson_save_question_options($question, $lesson) {
                 $answertext = $question->subanswers[$key];
                 if (!empty($questiontext) and !empty($answertext)) {
                     $answer = clone($defaultanswer);
-                    $answer->answer = $questiontext;
+                    $answer->answer = $questiontext['text'];
+                    $answer->answerformat   = $questiontext['format'];
                     $answer->response   = $answertext;
                     if ($i == 0) {
                         // first answer contains the correct answer jump
@@ -330,7 +337,9 @@ class qformat_default {
             return false;
         }
 
-        echo $OUTPUT->notification(get_string('importcount', 'lesson', sizeof($questions)));
+        //Avoid category as question type
+        echo $OUTPUT->notification(get_string('importcount', 'lesson',
+                $this->count_questions($questions)), 'notifysuccess');
 
         $count = 0;
 
@@ -338,6 +347,9 @@ class qformat_default {
 
         foreach ($questions as $question) {   // Process and store each question
             switch ($question->qtype) {
+                //TODO: Bad way to bypass category in data... Quickfix for MDL-27964
+                case 'category':
+                    break;
                 // the good ones
                 case SHORTANSWER :
                 case NUMERICAL :
@@ -346,7 +358,9 @@ class qformat_default {
                 case MATCH :
                     $count++;
 
-                    echo "<hr><p><b>$count</b>. ".$question->questiontext."</p>";
+                    //Show nice formated question in one line.
+                    echo "<hr><p><b>$count</b>. ".$this->format_question_text($question)."</p>";
+
                     $newpage = new stdClass;
                     $newpage->lessonid = $lesson->id;
                     $newpage->qtype = $this->qtypeconvert[$question->qtype];
@@ -436,6 +450,27 @@ class qformat_default {
         return true;
     }
 
+    /**
+     * Count all non-category questions in the questions array.
+     *
+     * @param array questions An array of question objects.
+     * @return int The count.
+     *
+     */
+    protected function count_questions($questions) {
+        $count = 0;
+        if (!is_array($questions)) {
+            return $count;
+        }
+        foreach ($questions as $question) {
+            if (!is_object($question) || !isset($question->qtype) ||
+                    ($question->qtype == 'category')) {
+                continue;
+            }
+            $count++;
+        }
+        return $count;
+    }
 
     function readdata($filename) {
     /// Returns complete file with an array, one item per line
@@ -505,7 +540,7 @@ class qformat_default {
 
         $question = new stdClass();
         $question->shuffleanswers = get_config('quiz', 'shuffleanswers');
-        $question->defaultgrade = 1;
+        $question->defaultmark = 1;
         $question->image = "";
         $question->usecase = 0;
         $question->multiplier = array();
@@ -519,6 +554,11 @@ class qformat_default {
         $question->qoption = 0;
         $question->layout = 1;
 
+        // this option in case the questiontypes class wants
+        // to know where the data came from
+        $question->export_process = true;
+        $question->import_process = true;
+
         return $question;
     }
 
@@ -529,6 +569,16 @@ class qformat_default {
         return true;
     }
 
+    /**
+     * Convert the question text to plain text, so it can safely be displayed
+     * during import to let the user see roughly what is going on.
+     */
+    protected function format_question_text($question) {
+        $formatoptions = new stdClass();
+        $formatoptions->noclean = true;
+        return html_to_text(format_text($question->questiontext,
+                $question->questiontextformat, $formatoptions), 0, false);
+    }
 }
 
 
index 6d2921f..0b00e20 100644 (file)
@@ -66,9 +66,13 @@ if ($data = $mform->get_data()) {
 
     require_sesskey();
 
-    if (!$importfile = $mform->get_importfile_name()) {
-        print_error('uploadproblem', 'moodle');
-        }
+    $realfilename = $mform->get_new_filename('questionfile');
+    //TODO: Leave all imported questions in Questionimport for now.
+    $importfile = "{$CFG->dataroot}/temp/questionimport/{$realfilename}";
+    make_upload_directory('temp/questionimport');
+    if (!$result = $mform->save_file('questionfile', $importfile, true)) {
+        throw new moodle_exception('uploadproblem');
+    }
 
     $formatclass = 'qformat_'.$data->format;
     $formatclassfile = $CFG->dirroot.'/question/format/'.$data->format.'/format.php';
@@ -102,4 +106,4 @@ if ($data = $mform->get_data()) {
     $mform->display();
 }
 
-echo $OUTPUT->footer();
+echo $OUTPUT->footer();
\ No newline at end of file
index 4bd93d4..765d565 100644 (file)
@@ -48,30 +48,49 @@ class lesson_import_form extends moodleform {
         $mform->setType('format', 'text');
         $mform->addRule('format', null, 'required');
 
-        $mform->addElement('file', 'newfile', get_string('upload'), array('size'=>'50'));
-        $mform->addRule('newfile', null, 'required');
-
-        $this->add_action_buttons(null, get_string("uploadthisfile"));
+        //Using filemanager as filepicker
+        $mform->addElement('filepicker', 'questionfile', get_string('upload'));
+        $mform->addRule('questionfile', null, 'required', null, 'client');
 
+        $this->add_action_buttons(null, get_string("import"));
     }
 
-    public function get_importfile_name(){
-        if ($this->is_submitted() and $this->is_validated()) {
-            // return the temporary filename to process
-            return $_FILES['newfile']['tmp_name'];
-        }else{
-            return  NULL;
+    /**
+     * Checks that a file has been uploaded, and that it is of a plausible type.
+     * @param array $data the submitted data.
+     * @param array $errors the errors so far.
+     * @return array the updated errors.
+     */
+    protected function validate_uploaded_file($data, $errors) {
+        global $CFG;
+
+        if (empty($data['questionfile'])) {
+            $errors['questionfile'] = get_string('required');
+            return $errors;
+        }
+
+        $files = $this->get_draft_files('questionfile');
+        if (count($files) < 1) {
+            $errors['questionfile'] = get_string('required');
+            return $errors;
         }
-    }
 
-    public function get_importfile_realname(){
-        if ($this->is_submitted() and $this->is_validated()) {
-            // return the temporary filename to process
-            // TODO change this to use the files API properly.
-            return $_FILES['newfile']['name'];
-        }else{
-            return  NULL;
+        $formatfile = $CFG->dirroot.'/question/format/'.$data['format'].'/format.php';
+        if (!is_readable($formatfile)) {
+            throw new moodle_exception('formatnotfound', 'lesson', '', $data['format']);
         }
+
+        require_once($formatfile);
+
+        $classname = 'qformat_' . $data['format'];
+        $qformat = new $classname();
+
+        return $errors;
     }
 
+    public function validation($data, $files) {
+        $errors = parent::validation($data, $files);
+        $errors = $this->validate_uploaded_file($data, $errors);
+        return $errors;
+    }
 }
\ No newline at end of file
index abc853a..372cf8b 100644 (file)
@@ -109,6 +109,7 @@ $string['confirmdeletionofthispage'] = 'Confirm deletion of this page';
 $string['congratulations'] = 'Congratulations - end of lesson reached';
 $string['continue'] = 'Continue';
 $string['continuetoanswer'] = 'Continue to change answers.';
+$string['continuetonextpage'] = 'Continue to next page.';
 $string['correctanswerjump'] = 'Correct answer jump';
 $string['correctanswerscore'] = 'Correct answer score';
 $string['correctresponse'] = 'Correct response';
@@ -166,11 +167,13 @@ $string['essayemailsubject'] = 'Your grade for {$a} question';
 $string['essays'] = 'Essays';
 $string['essayscore'] = 'Essay score';
 $string['fileformat'] = 'File format';
+$string['finish'] = 'Finish';
 $string['firstanswershould'] = 'First answer should jump to the "Correct" page';
 $string['firstwrong'] = 'Unfortunately you cannot earn this one point, because your response was not correct.  Would you like to keep guessing, just for the sheer joy of learning (but for no point credit)?';
 $string['flowcontrol'] = 'Flow control';
 $string['full'] = 'Expanded';
 $string['general'] = 'General';
+$string['gotoendoflesson'] = 'Go to the end of the lesson';
 $string['grade'] = 'Grade';
 $string['gradebetterthan'] = 'Grade better than (&#37;)';
 $string['gradebetterthanerror'] = 'Earn a grade better than {$a} percent';
@@ -378,6 +381,7 @@ $string['studentattemptlesson'] = '{$a->lastname}, {$a->firstname}\'s attempt nu
 $string['studentname'] = '{$a} Name';
 $string['studentoneminwarning'] = 'Warning: You have 1 minute or less to finish the lesson.';
 $string['studentresponse'] = '{$a}\'s response';
+$string['submit'] = 'Submit';
 $string['submitname'] = 'Submit name';
 $string['teacherjumpwarning'] = 'An {$a->cluster} jump or an {$a->unseen} jump is being used in this lesson.  The next page jump will be used instead.  Login as a student to test these jumps.';
 $string['teacherongoingwarning'] = 'Ongoing score is only displayed for student.  Login as a student to test ongoing score';
index cfb1bbc..1b4906e 100644 (file)
@@ -989,7 +989,7 @@ function lesson_get_file_info($browser, $areas, $course, $cm, $context, $fileare
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function lesson_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function lesson_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-lesson-*'=>get_string('page-mod-lesson-x', 'lesson'));
     return $module_pagetype;
 }
index 84a8661..f26f1be 100644 (file)
@@ -1961,13 +1961,15 @@ abstract class lesson_page extends lesson_base {
                     $attempt->retry = $nretakes - 1; // they are going through on review, $nretakes will be too high
                 }
 
-                $DB->insert_record("lesson_attempts", $attempt);
+                if ($this->lesson->retake || (!$this->lesson->retake && $nretakes == 0)) {
+                    $DB->insert_record("lesson_attempts", $attempt);
+                }
                 // "number of attempts remaining" message if $this->lesson->maxattempts > 1
                 // displaying of message(s) is at the end of page for more ergonomic display
                 if (!$result->correctanswer && ($result->newpageid == 0)) {
                     // wrong answer and student is stuck on this page - check how many attempts
                     // the student has had at this page/question
-                    $nattempts = $DB->count_records("lesson_attempts", array("pageid"=>$this->properties->id, "userid"=>$USER->id, "retry" => $nretakes));
+                    $nattempts = $DB->count_records("lesson_attempts", array("pageid"=>$this->properties->id, "userid"=>$USER->id, "retry" => $attempt->retry));
                     // retreive the number of attempts left counter for displaying at bottom of feedback page
                     if ($nattempts >= $this->lesson->maxattempts) {
                         if ($this->lesson->maxattempts > 1) { // don't bother with message if only one attempt
index 2f7d4f9..b1c8136 100644 (file)
@@ -51,14 +51,14 @@ class lesson_page_type_essay extends lesson_page {
     public function display($renderer, $attempt) {
         global $PAGE, $CFG, $USER;
 
-        $mform = new lesson_display_answer_form_essay($CFG->wwwroot.'/mod/lesson/continue.php', array('contents'=>$this->get_contents()));
+        $mform = new lesson_display_answer_form_essay($CFG->wwwroot.'/mod/lesson/continue.php', array('contents'=>$this->get_contents(), 'lessonid'=>$this->lesson->id));
 
         $data = new stdClass;
         $data->id = $PAGE->cm->id;
         $data->pageid = $this->properties->id;
         if (isset($USER->modattempts[$this->lesson->id])) {
             $essayinfo = unserialize($attempt->useranswer);
-            $data->answer = array('text'=>$essayinfo->answer, 'format'=>FORMAT_HTML);
+            $data->answer = $essayinfo->answer;
         }
         $mform->set_data($data);
         return $mform->display();
@@ -252,6 +252,20 @@ class lesson_display_answer_form_essay extends moodleform {
         $mform = $this->_form;
         $contents = $this->_customdata['contents'];
 
+        $hasattempt = false;
+        $attrs = '';
+        $useranswer = '';
+        $useranswerraw = '';
+        if (isset($this->_customdata['lessonid'])) {
+            $lessonid = $this->_customdata['lessonid'];
+            if (isset($USER->modattempts[$lessonid]->useranswer) && !empty($USER->modattempts[$lessonid]->useranswer)) {
+                $attrs = array('disabled' => 'disabled');
+                $hasattempt = true;
+                $useranswer = unserialize($USER->modattempts[$lessonid]->useranswer);
+                $useranswer = htmlspecialchars_decode($useranswer->answer, ENT_QUOTES);
+            }
+        }
+
         $mform->addElement('header', 'pageheader');
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
@@ -266,10 +280,16 @@ class lesson_display_answer_form_essay extends moodleform {
         $mform->addElement('hidden', 'pageid');
         $mform->setType('pageid', PARAM_INT);
 
-        $mform->addElement('editor', 'answer', get_string('youranswer', 'lesson'), null, null);
-        $mform->setType('answer', PARAM_RAW);
-
-        $this->add_action_buttons(null, get_string("pleaseenteryouranswerinthebox", "lesson"));
+        if ($hasattempt) {
+            $mform->addElement('hidden', 'answer', $useranswerraw);
+            $mform->setType('answer', PARAM_CLEANHTML);
+            $mform->addElement('html', $OUTPUT->container(get_string('youranswer', 'lesson'), 'youranswer'));
+            $mform->addElement('html', $OUTPUT->container($useranswer, 'reviewessay'));
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $mform->addElement('editor', 'answer', get_string('youranswer', 'lesson'), null, null);
+            $mform->setType('answer', PARAM_RAW);
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
     }
-
 }
index 3e40c63..e9ffa09 100644 (file)
@@ -61,7 +61,13 @@ class lesson_page_type_matching extends lesson_page {
     protected function make_answer_form($attempt=null) {
         global $USER, $CFG;
         // don't shuffle answers (could be an option??)
-        $answers = array_slice($this->get_answers(), 2);
+        $getanswers = array_slice($this->get_answers(), 2);
+
+        $answers = array();
+        foreach ($getanswers as $getanswer) {
+            $answers[$getanswer->id] = $getanswer;
+        }
+
         $responses = array();
         foreach ($answers as $answer) {
             // get all the response
@@ -487,6 +493,13 @@ class lesson_display_answer_form_matching extends moodleform {
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
 
+        $hasattempt = false;
+        $disabled = '';
+        if (isset($useranswers) && !empty($useranswers)) {
+            $hasattempt = true;
+            $disabled = array('disabled' => 'disabled');
+        }
+
         $options = new stdClass;
         $options->para = false;
         $options->noclean = true;
@@ -501,19 +514,28 @@ class lesson_display_answer_form_matching extends moodleform {
         foreach ($answers as $answer) {
             $mform->addElement('html', '<div class="answeroption">');
             if ($answer->response != NULL) {
-                $mform->addElement('select', 'response['.$answer->id.']', format_text($answer->answer,$answer->answerformat,$options), $responseoptions);
-                $mform->setType('response['.$answer->id.']', PARAM_TEXT);
-                if (isset($USER->modattempts[$lessonid])) {
-                    $mform->setDefault('response['.$answer->id.']', htmlspecialchars(trim($answers[$useranswers[$i]]->response))); //TODO: this is suspicious
+                $responseid = 'response['.$answer->id.']';
+                if ($hasattempt) {
+                    $responseid = 'response_'.$answer->id;
+                    $mform->addElement('hidden', 'response['.$answer->id.']', htmlspecialchars(trim($answers[$useranswers[$i]]->response)));
+                    $mform->setType('response['.$answer->id.']', PARAM_TEXT);
+                }
+                $mform->addElement('select', $responseid, format_text($answer->answer,$answer->answerformat,$options), $responseoptions, $disabled);
+                $mform->setType($responseid, PARAM_TEXT);
+                if ($hasattempt) {
+                    $mform->setDefault($responseid, htmlspecialchars(trim($answers[$useranswers[$i]]->response))); //TODO: this is suspicious
                 } else {
-                    $mform->setDefault('response['.$answer->id.']', 'answeroption');
+                    $mform->setDefault($responseid, 'answeroption');
                 }
             }
             $mform->addElement('html', '</div>');
             $i++;
         }
-
-        $this->add_action_buttons(null, get_string("pleasematchtheabovepairs", "lesson"));
+        if ($hasattempt) {
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
     }
 
 }
index f29268f..078af89 100644 (file)
@@ -490,6 +490,13 @@ class lesson_display_answer_form_multichoice_singleanswer extends moodleform {
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
 
+        $hasattempt = false;
+        $disabled = '';
+        if (isset($USER->modattempts[$lessonid]) && !empty($USER->modattempts[$lessonid])) {
+            $hasattempt = true;
+            $disabled = array('disabled' => 'disabled');
+        }
+
         $options = new stdClass;
         $options->para = false;
         $options->noclean = true;
@@ -503,16 +510,20 @@ class lesson_display_answer_form_multichoice_singleanswer extends moodleform {
         $i = 0;
         foreach ($answers as $answer) {
             $mform->addElement('html', '<div class="answeroption">');
-            $mform->addElement('radio','answerid',null,format_text($answer->answer, $answer->answerformat, $options),$answer->id);
+            $mform->addElement('radio','answerid',null,format_text($answer->answer, $answer->answerformat, $options),$answer->id, $disabled);
             $mform->setType('answer'.$i, PARAM_INT);
-            if (isset($USER->modattempts[$lessonid]) && $answer->id == $USER->modattempts[$lessonid]->answerid) {
-                $mform->setDefault('answerid', true);
+            if ($hasattempt && $answer->id == $USER->modattempts[$lessonid]->answerid) {
+                $mform->setDefault('answerid', $USER->modattempts[$lessonid]->answerid);
             }
             $mform->addElement('html', '</div>');
             $i++;
         }
 
-        $this->add_action_buttons(null, get_string("pleasecheckoneanswer", "lesson"));
+        if ($hasattempt) {
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
     }
 
 }
index 9e5c0f5..8681fdf 100644 (file)
@@ -50,7 +50,7 @@ class lesson_page_type_shortanswer extends lesson_page {
     }
     public function display($renderer, $attempt) {
         global $USER, $CFG, $PAGE;
-        $mform = new lesson_display_answer_form_shortanswer($CFG->wwwroot.'/mod/lesson/continue.php', array('contents'=>$this->get_contents()));
+        $mform = new lesson_display_answer_form_shortanswer($CFG->wwwroot.'/mod/lesson/continue.php', array('contents'=>$this->get_contents(), 'lessonid'=>$this->lesson->id));
         $data = new stdClass;
         $data->id = $PAGE->cm->id;
         $data->pageid = $this->properties->id;
@@ -328,10 +328,20 @@ class lesson_add_page_form_shortanswer extends lesson_add_page_form_base {
 class lesson_display_answer_form_shortanswer extends moodleform {
 
     public function definition() {
-        global $OUTPUT;
+        global $OUTPUT, $USER;
         $mform = $this->_form;
         $contents = $this->_customdata['contents'];
 
+        $hasattempt = false;
+        $attrs = array('size'=>'50', 'maxlength'=>'200');
+        if (isset($this->_customdata['lessonid'])) {
+            $lessonid = $this->_customdata['lessonid'];
+            if (isset($USER->modattempts[$lessonid]->useranswer)) {
+                $attrs['readonly'] = 'readonly';
+                $hasattempt = true;
+            }
+        }
+
         $mform->addElement('header', 'pageheader');
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
@@ -346,10 +356,14 @@ class lesson_display_answer_form_shortanswer extends moodleform {
         $mform->addElement('hidden', 'pageid');
         $mform->setType('pageid', PARAM_INT);
 
-        $mform->addElement('text', 'answer', get_string('youranswer', 'lesson'), array('size'=>'50', 'maxlength'=>'200'));
+        $mform->addElement('text', 'answer', get_string('youranswer', 'lesson'), $attrs);
         $mform->setType('answer', PARAM_TEXT);
 
-        $this->add_action_buttons(null, get_string("pleaseenteryouranswerinthebox", "lesson"));
+        if ($hasattempt) {
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
     }
 
 }
index 61a1a7e..6b8977b 100644 (file)
@@ -303,6 +303,13 @@ class lesson_display_answer_form_truefalse extends moodleform {
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
 
+        $hasattempt = false;
+        $disabled = '';
+        if (isset($USER->modattempts[$lessonid]) && !empty($USER->modattempts[$lessonid])) {
+            $hasattempt = true;
+            $disabled = array('disabled' => 'disabled');
+        }
+
         $options = new stdClass();
         $options->para = false;
         $options->noclean = true;
@@ -316,16 +323,28 @@ class lesson_display_answer_form_truefalse extends moodleform {
         $i = 0;
         foreach ($answers as $answer) {
             $mform->addElement('html', '<div class="answeroption">');
-            $mform->addElement('radio', 'answerid', null, format_text($answer->answer, $answer->answerformat, $options), $answer->id);
-            $mform->setType('answerid', PARAM_INT);
-            if (isset($USER->modattempts[$lessonid]) && $answer->id == $attempt->answerid) {
-                $mform->setDefault('answerid', true);
+            $ansid = 'answerid';
+            if ($hasattempt) {
+                $ansid = 'answer_id';
+            }
+
+            $mform->addElement('radio', $ansid, null, format_text($answer->answer, $answer->answerformat, $options), $answer->id, $disabled);
+            $mform->setType($ansid, PARAM_INT);
+            if ($hasattempt && $answer->id == $USER->modattempts[$lessonid]->answerid) {
+                $mform->setDefault($ansid, $attempt->answerid);
+                $mform->addElement('hidden', 'answerid', $answer->id);
+                $mform->setType('answerid', PARAM_INT);
             }
             $mform->addElement('html', '</div>');
             $i++;
         }
 
-        $this->add_action_buttons(null, get_string("pleasecheckoneanswer", "lesson"));
+        if ($hasattempt) {
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
+
     }
 
 }
index 99028da..fd4541a 100644 (file)
@@ -28,4 +28,5 @@
 /**
  * Style for view.php
  **/
-#page-mod-lesson-view .password-form .submitbutton {display: inline;}
\ No newline at end of file
+#page-mod-lesson-view .password-form .submitbutton {display: inline;}
+.path-mod-lesson .reviewessay {width:40%; border:1px solid #DDDDDD; background-color: #EEEEEE;}
index c82d589..855b755 100644 (file)
@@ -60,6 +60,12 @@ $canmanage = has_capability('mod/lesson:manage', $context);
 
 $lessonoutput = $PAGE->get_renderer('mod_lesson');
 
+$reviewmode = false;
+$userhasgrade = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
+if ($userhasgrade && !$lesson->retake) {
+    $reviewmode = true;
+}
+
 /// Check these for students only TODO: Find a better method for doing this!
 ///     Check lesson availability
 ///     Check for password
@@ -316,11 +322,14 @@ if ($pageid != LESSON_EOL) {
                     $a->minquestions = $lesson->minquestions;
                     $lesson->add_message(get_string('numberofpagesviewednotice', 'lesson', $a));
                 }
-                $lesson->add_message(get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned), 'notify');
+
                 $a = new stdClass;
                 $a->grade = number_format($gradeinfo->grade * $lesson->grade / 100, 1);
                 $a->total = $lesson->grade;
-                $lesson->add_message(get_string('yourcurrentgradeisoutof', 'lesson', $a), 'notify');
+                if (!$reviewmode && !$lesson->retake){
+                    $lesson->add_message(get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned), 'notify');
+                    $lesson->add_message(get_string('yourcurrentgradeisoutof', 'lesson', $a), 'notify');
+                }
             }
         }
     } else {
@@ -356,6 +365,7 @@ if ($pageid != LESSON_EOL) {
                 print_error('cannotfindpreattempt', 'lesson');
             }
             $attempt = end($attempts);
+            $USER->modattempts[$lesson->id] = $attempt;
         } else {
             $attempt = false;
         }
@@ -387,7 +397,7 @@ if ($pageid != LESSON_EOL) {
         echo $OUTPUT->heading(get_string('attempt', 'lesson', $retries));
     }
     /// This calculates and prints the ongoing score
-    if ($lesson->ongoing && !empty($pageid)) {
+    if ($lesson->ongoing && !empty($pageid) && !$reviewmode) {
         echo $lessonoutput->ongoing_score($lesson);
     }
     if ($lesson->displayleft) {
@@ -538,17 +548,18 @@ if ($pageid != LESSON_EOL) {
         // $ntries is decremented above
         if (!$attempts = $lesson->get_attempts($ntries)) {
             $attempts = array();
+            $url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id));
+        } else {
+            $firstattempt = current($attempts);
+            $pageid = $firstattempt->pageid;
+            // IF the student wishes to review, need to know the last question page that the student answered.  This will help to make
+            // sure that the student can leave the lesson via pushing the continue button.
+            $lastattempt = end($attempts);
+            $USER->modattempts[$lesson->id] = $lastattempt->pageid;
+
+            $url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id, 'pageid'=>$pageid));
         }
-        $firstattempt = current($attempts);
-        $pageid = $firstattempt->pageid;
-        // IF the student wishes to review, need to know the last question page that the student answered.  This will help to make
-        // sure that the student can leave the lesson via pushing the continue button.
-        $lastattempt = end($attempts);
-        $USER->modattempts[$lesson->id] = $lastattempt->pageid;
-
-        $url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id, 'pageid'=>$pageid));
         $lessoncontent .= html_writer::link($url, get_string('reviewlesson', 'lesson'), array('class' => 'centerpadded lessonbutton standardbutton'));
-
     } elseif ($lesson->modattempts && $canmanage) {
         $lessoncontent .= $lessonoutput->paragraph(get_string("modattemptsnoteacher", "lesson"), 'centerpadded');
     }
index 300051b..2fcd026 100644 (file)
@@ -411,7 +411,7 @@ function page_extend_navigation($navigation, $course, $module, $cm) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function page_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function page_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-page-*'=>get_string('page-mod-page-x', 'page'));
     return $module_pagetype;
 }
index 4cf6fcf..3eadb0b 100644 (file)
@@ -1710,7 +1710,7 @@ function mod_quiz_question_pluginfile($course, $context, $component,
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function quiz_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function quiz_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-quiz-*'=>get_string('page-mod-quiz-x', 'quiz'));
     return $module_pagetype;
 }
index 803c89b..be79a32 100644 (file)
@@ -436,7 +436,7 @@ function resource_pluginfile($course, $cm, $context, $filearea, $args, $forcedow
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function resource_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function resource_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-resource-*'=>get_string('page-mod-resource-x', 'resource'));
     return $module_pagetype;
 }
index bbddc92..b799907 100644 (file)
@@ -1078,7 +1078,7 @@ function scorm_print_overview($courses, &$htmlarray) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function scorm_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function scorm_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-scorm-*'=>get_string('page-mod-scorm-x', 'scorm'));
     return $module_pagetype;
 }
index 9c3d380..bed1fa1 100644 (file)
@@ -871,7 +871,7 @@ function survey_extend_settings_navigation($settings, $surveynode) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function survey_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function survey_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-survey-*'=>get_string('page-mod-survey-x', 'survey'));
     return $module_pagetype;
 }
index 9e43a41..e354511 100644 (file)
@@ -318,7 +318,7 @@ function url_extend_navigation($navigation, $course, $module, $cm) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function url_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function url_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-url-*'=>get_string('page-mod-url-x', 'url'));
     return $module_pagetype;
 }
index 42c8429..7f9a3d6 100644 (file)
@@ -665,7 +665,7 @@ function wiki_comment_validate($comment_param) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function wiki_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function wiki_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array(
         'mod-wiki-*'=>get_string('page-mod-wiki-x', 'wiki'),
         'mod-wiki-view'=>get_string('page-mod-wiki-view', 'wiki'),
index a4d86a3..26880ed 100644 (file)
@@ -1382,7 +1382,7 @@ function workshop_extend_settings_navigation(settings_navigation $settingsnav, n
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function workshop_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function workshop_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-workshop-*'=>get_string('page-mod-workshop-x', 'workshop'));
     return $module_pagetype;
 }
index f01d870..0744211 100644 (file)
@@ -284,6 +284,6 @@ function note_delete_all($courseid) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function note_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function note_page_type_list($pagetype, $parentcontext, $currentcontext) {
     return array('notes-*'=>get_string('page-notes-x', 'notes'));
 }
index 7d33ccb..2284a41 100644 (file)
@@ -1124,7 +1124,7 @@ function tag_unset_flag($tagids) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function tag_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function tag_page_type_list($pagetype, $parentcontext, $currentcontext) {
     return array(
         'tag-*'=>get_string('page-tag-x', 'tag'),
         'tag-index'=>get_string('page-tag-index', 'tag'),
index fdc28bd..ac8cd74 100644 (file)
@@ -355,10 +355,6 @@ class moodle_user_external extends external_api {
     public static function get_users_by_id($userids) {
         global $CFG, $USER, $DB;
         require_once($CFG->dirroot . "/user/lib.php");
-        require_once($CFG->dirroot . "/user/profile/lib.php"); //custom field library
-        require_once($CFG->dirroot . "/lib/filelib.php"); // file handling on description and friends
-
-        $isadmin = is_siteadmin($USER);
 
         $params = self::validate_parameters(self::get_users_by_id_parameters(),
                 array('userids'=>$userids));
@@ -371,205 +367,29 @@ class moodle_user_external extends external_api {
         $users = $DB->get_recordset_sql($usersql, $params);
 
         $result = array();
+        $hasuserupdatecap = has_capability('moodle/user:update', get_system_context());
         foreach ($users as $user) {
             if (!empty($user->deleted)) {
                 continue;
             }
             context_instance_preload($user);
-            // cached
-            $context = get_context_instance(CONTEXT_USER, $user->id);
-            $hasviewdetailscap = has_capability('moodle/user:viewdetails', $context);
-            $hasuserupdatecap = has_capability('moodle/user:update', get_system_context());
-
-            self::validate_context($context);
-
+            $usercontext = get_context_instance(CONTEXT_USER, $user->id);
+            self::validate_context($usercontext);
             $currentuser = ($user->id == $USER->id);
 
-            if (!$currentuser && !$hasviewdetailscap && !has_coursecontact_role($user->id)) {
-                throw new moodle_exception('usernotavailable', 'error');
-            }
-
-            $userarray = array();
-
-            //basic fields
-            $userarray['id'] = $user->id;
-            if ($isadmin) {
-                $userarray['username'] = $user->username;
-            }
-            if ($isadmin or has_capability('moodle/site:viewfullnames', $context)) {
-                $userarray['firstname'] = $user->firstname;
-                $userarray['lastname'] = $user->lastname;
-            }
-            $userarray['fullname'] = fullname($user);
-
-            //fields matching permissions from /user/editadvanced.php
-            if ($currentuser or $hasuserupdatecap) {
-                $userarray['auth'] = $user->auth;
-                $userarray['confirmed'] = $user->confirmed;
-                $userarray['idnumber'] = $user->idnumber;
-                $userarray['lang'] = $user->lang;
-                $userarray['theme'] = $user->theme;
-                $userarray['timezone'] = $user->timezone;
-                $userarray['mailformat'] = $user->mailformat;
-            }
-
-            //Custom fields (matching /user/profil/lib.php - profile_display_fields code logic)
-            $fields = $DB->get_recordset_sql("SELECT f.*
-                                                FROM {user_info_field} f
-                                                JOIN {user_info_category} c
-                                                     ON f.categoryid=c.id
-                                            ORDER BY c.sortorder ASC, f.sortorder ASC");
-            foreach ($fields as $field) {
-                require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
-                $newfield = 'profile_field_'.$field->datatype;
-                $formfield = new $newfield($field->id, $user->id);
-                if ($formfield->is_visible() and !$formfield->is_empty()) {
-                    $userarray['customfields'][] =
-                        array('name' => $formfield->field->name, 'value' => $formfield->data,
-                            'type' => $field->datatype, 'shortname' => $formfield->field->shortname);
-                }
-            }
-            $fields->close();
-
-            //image profiles urls (public, no permission required in fact)
-            $profileimageurl = moodle_url::make_pluginfile_url($context->id, 'user', 'icon', NULL, '/', 'f1');
-            $userarray['profileimageurl'] = $profileimageurl->out(false);
-            $profileimageurlsmall = moodle_url::make_pluginfile_url($context->id, 'user', 'icon', NULL, '/', 'f2');
-            $userarray['profileimageurlsmall'] = $profileimageurlsmall->out(false);
-
-            //hidden user field
-            if (has_capability('moodle/user:viewhiddendetails', $context)) {
-                $hiddenfields = array();
-            } else {
-                $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
-            }
-
-            if (isset($user->description) && (!isset($hiddenfields['description']) or $isadmin)) {
-                if (empty($CFG->profilesforenrolledusersonly) || $currentuser) {
-                    $user->description = file_rewrite_pluginfile_urls($user->description, 'pluginfile.php', $context->id, 'user', 'profile', null);
-                    $userarray['description'] = $user->description;
-                    $userarray['descriptionformat'] = $user->descriptionformat;
-                }
-            }
-
-            if ((! isset($hiddenfields['country']) or $isadmin) && $user->country) {
-                $userarray['country'] = $user->country;
-            }
-
-            if ((! isset($hiddenfields['city']) or $isadmin) && $user->city) {
-                $userarray['city'] = $user->city;
-            }
-
-            if (has_capability('moodle/user:viewhiddendetails', $context)) {
-                if ($user->address) {
-                    $userarray['address'] = $user->address;
-                }
-                if ($user->phone1) {
-                    $userarray['phone1'] = $user->phone1;
-                }
-                if ($user->phone2) {
-                    $userarray['phone2'] = $user->phone2;
-                }
-            }
-
-            if ($currentuser
-              or $user->maildisplay == 1
-              or has_capability('moodle/course:useremail', $context)
-              or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER))) {
-                $userarray['email'] = $user->email;;
-            }
-
-            if ($user->url && (!isset($hiddenfields['webpage']) or $isadmin)) {
-                $url = $user->url;
-                if (strpos($user->url, '://') === false) {
-                    $url = 'http://'. $url;
-                }
-                $user->url = clean_param($user->url, PARAM_URL);
-                $userarray['url'] = $user->url;
-            }
-
-            if ($user->icq && (!isset($hiddenfields['icqnumber']) or $isadmin)) {
-                $userarray['icq'] = $user->icq;
-            }
-
-            if ($user->skype && (!isset($hiddenfields['skypeid']) or $isadmin)) {
-                $userarray['skype'] = $user->skype;
-            }
-            if ($user->yahoo && (!isset($hiddenfields['yahooid']) or $isadmin)) {
-                $userarray['yahoo'] = $user->yahoo;
-            }
-            if ($user->aim && (!isset($hiddenfields['aimid']) or $isadmin)) {
-                $userarray['aim'] = $user->aim;
-            }
-            if ($user->msn && (!isset($hiddenfields['msnid']) or $isadmin)) {
-                $userarray['msn'] = $user->msn;
-            }
-
-            if ((!isset($hiddenfields['firstaccess'])) or $isadmin) {
-                if ($user->firstaccess) {
-                    $userarray['firstaccess'] = $user->firstaccess;
-                } else {
-                    $userarray['firstaccess'] = 0;
-                }
-            }
-            if ((!isset($hiddenfields['lastaccess'])) or $isadmin) {
-                if ($user->lastaccess) {
-                    $userarray['lastaccess'] = $user->lastaccess;
-                } else {
-                    $userarray['lastaccess'] = 0;
+            if ($userarray  = user_get_user_details($user)) {
+                //fields matching permissions from /user/editadvanced.php
+                if ($currentuser or $hasuserupdatecap) {
+                    $userarray['auth']       = $user->auth;
+                    $userarray['confirmed']  = $user->confirmed;
+                    $userarray['idnumber']   = $user->idnumber;
+                    $userarray['lang']       = $user->lang;
+                    $userarray['theme']      = $user->theme;
+                    $userarray['timezone']   = $user->timezone;
+                    $userarray['mailformat'] = $user->mailformat;
                 }
+                $result[] = $userarray;
             }
-            /// Printing tagged interests
-            if (!empty($CFG->usetags)) {
-                require_once($CFG->dirroot . '/tag/lib.php');
-                if ($interests = tag_get_tags_csv('user', $user->id, TAG_RETURN_TEXT) ) {
-                    $userarray['interests'] = $interests;
-                }
-            }
-
-            //Departement/Institution are not displayed on any profile, however you can get them from editing profile.
-            if ($isadmin or $currentuser) {
-                if ($user->institution) {
-                    $userarray['institution'] = $user->institution;
-                }
-                if (isset($user->department)) { //isset because it's ok to have department 0
-                    $userarray['department'] = $user->department;
-                }
-            }
-
-            //list of courses where the user is enrolled
-            $enrolledcourses = array();
-            if (!isset($hiddenfields['mycourses'])) {
-                if ($mycourses = enrol_get_users_courses($user->id, true, NULL, 'visible DESC,sortorder ASC')) {
-                    $courselisting = '';
-                    foreach ($mycourses as $mycourse) {
-                        if ($mycourse->category) {
-                            if ($mycourse->visible == 0) {
-                                $ccontext = get_context_instance(CONTEXT_COURSE, $mycourse->id);
-                                if (!has_capability('moodle/course:viewhiddencourses', $ccontext)) {
-                                    continue;
-                                }
-                            }
-                            $enrolledcourse = array();
-                            $enrolledcourse['id'] = $mycourse->id;
-                            $enrolledcourse['fullname'] = $mycourse->fullname;
-                            $enrolledcourses[] = $enrolledcourse;
-                        }
-                    }
-                    $userarray['enrolledcourses'] = $enrolledcourses;
-                }
-            }
-
-            //user preferences
-            if ($currentuser) {
-                $preferences = array();
-                $userpreferences = get_user_preferences();
-                 foreach($userpreferences as $prefname => $prefvalue) {
-                    $preferences[] = array('name' => $prefname, 'value' => $prefvalue);
-                 }
-                 $userarray['preferences'] = $preferences;
-            }
-            $result[] = $userarray;
         }
         $users->close();
 
@@ -637,7 +457,8 @@ class moodle_user_external extends external_api {
                         new external_single_structure(
                             array(
                                 'id'  => new external_value(PARAM_INT, 'Id of the course'),
-                                'fullname' => new external_value(PARAM_RAW, 'Fullname of the course')
+                                'fullname'  => new external_value(PARAM_RAW, 'Fullname of the course'),
+                                'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
                             )
                     ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
                 )
@@ -671,11 +492,6 @@ class moodle_user_external extends external_api {
     public static function get_course_participants_by_id($userlist) {
         global $CFG, $USER, $DB;
         require_once($CFG->dirroot . "/user/lib.php");
-        require_once($CFG->dirroot . "/user/profile/lib.php"); //custom field library
-        require_once($CFG->dirroot . "/lib/filelib.php");      // file handling on description and friends
-
-        $isadmin = is_siteadmin($USER);
-
         $params = self::validate_parameters(self::get_course_participants_by_id_parameters(), array('userlist'=>$userlist));
 
         $userids = array();
@@ -713,190 +529,217 @@ class moodle_user_external extends external_api {
                 continue;
             }
             context_instance_preload($user);
-            $usercontext = get_context_instance(CONTEXT_USER, $user->id);
             $course = $courses[$courseids[$user->id]];
             $context = get_context_instance(CONTEXT_COURSE, $courseids[$user->id]);
-            $hasviewdetailscap = has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext);
-
             self::validate_context($context);
-
-            $currentuser = ($user->id == $USER->id);
-
-            if (!$currentuser && !$hasviewdetailscap && !has_coursecontact_role($user->id)) {
-                throw new moodle_exception('usernotavailable', 'error');
-            }
-            $userarray = array();
-
-            //basic fields
-            $userarray['id'] = $user->id;
-            if ($isadmin) {
-                $userarray['username'] = $user->username;
-            }
-            if ($isadmin or has_capability('moodle/site:viewfullnames', $context)) {
-                $userarray['firstname'] = $user->firstname;
-                $userarray['lastname'] = $user->lastname;
-            }
-            $userarray['fullname'] = fullname($user);
-
-            //Custom fields (matching /user/profile/lib.php - profile_display_fields code logic)
-            $userarray['customfields'] = array();
-
-            $fields = $DB->get_recordset_sql("SELECT f.*
-                                                FROM {user_info_field} f
-                                                JOIN {user_info_category} c
-                                                     ON f.categoryid=c.id
-                                            ORDER BY c.sortorder ASC, f.sortorder ASC");
-            foreach ($fields as $field) {
-                require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
-                $newfield = 'profile_field_'.$field->datatype;
-                $formfield = new $newfield($field->id, $user->id);
-                if ($formfield->is_visible() and !$formfield->is_empty()) {
-                    $userarray['customfields'][] =
-                        array('name' => $formfield->field->name, 'value' => $formfield->data,
-                            'type' => $field->datatype, 'shortname' => $formfield->field->shortname);
-                }
-            }
-            $fields->close();
-
-            //image profiles urls (public, no permission required in fact)
-            $profileimageurl = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f1');
-            $userarray['profileimageurl'] = $profileimageurl->out(false);
-            $profileimageurlsmall = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f2');
-            $userarray['profileimageurlsmall'] = $profileimageurlsmall->out(false);
-
-            //hidden user field
-            if (has_capability('moodle/course:viewhiddenuserfields', $context)) {
-                $hiddenfields = array();
-            } else {
-                $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
-            }
-
-            if (isset($user->description) && (!isset($hiddenfields['description']) or $isadmin)) {
-                if (empty($CFG->profilesforenrolledusersonly) || $currentuser) {
-                    $user->description = file_rewrite_pluginfile_urls($user->description, 'pluginfile.php', $context->id, 'user', 'profile', null);
-                    $userarray['description'] = $user->description;
-                    $userarray['descriptionformat'] = $user->descriptionformat;
-                }
-            }
-
-            if ((! isset($hiddenfields['country']) or $isadmin) && $user->country) {
-                $userarray['country'] = $user->country;
+            if ($userarray = user_get_user_details($user, $course)) {
+                $result[] = $userarray;
             }
+        }
 
-            if ((! isset($hiddenfields['city']) or $isadmin) && $user->city) {
-                $userarray['city'] = $user->city;
-            }
+        $users->close();
 
-            if (has_capability('moodle/course:viewhiddenuserfields', $context)) {
-                if ($user->address) {
-                    $userarray['address'] = $user->address;
-                }
-                if ($user->phone1) {
-                    $userarray['phone1'] = $user->phone1;
-                }
-                if ($user->phone2) {
-                    $userarray['phone2'] = $user->phone2;
-                }
-            }
+        return $result;
+    }
 
-            if ($currentuser
-              or $user->maildisplay == 1
-              or has_capability('moodle/course:useremail', $context)
-              or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER))) {
-                $userarray['email'] = $user->email;;
-            }
+    /**
+     * Returns description of method result value
+     * @return external_description
+     */
+    public static function get_course_participants_by_id_returns() {
+        return new external_multiple_structure(
+            new external_single_structure(
+                array(
+                    'id'    => new external_value(PARAM_NUMBER, 'ID of the user'),
+                    'username'    => new external_value(PARAM_RAW, 'Username policy is defined in Moodle security config', VALUE_OPTIONAL),
+                    'firstname'   => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
+                    'lastname'    => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
+                    'fullname'    => new external_value(PARAM_NOTAGS, 'The fullname of the user'),
+                    'email'       => new external_value(PARAM_TEXT, 'An email address - allow email as root@localhost', VALUE_OPTIONAL),
+                    'address'     => new external_value(PARAM_MULTILANG, 'Postal address', VALUE_OPTIONAL),
+                    'phone1'      => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL),
+                    'phone2'      => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL),
+                    'icq'         => new external_value(PARAM_NOTAGS, 'icq number', VALUE_OPTIONAL),
+                    'skype'       => new external_value(PARAM_NOTAGS, 'skype id', VALUE_OPTIONAL),
+                    'yahoo'       => new external_value(PARAM_NOTAGS, 'yahoo id', VALUE_OPTIONAL),
+                    'aim'         => new external_value(PARAM_NOTAGS, 'aim id', VALUE_OPTIONAL),
+                    'msn'         => new external_value(PARAM_NOTAGS, 'msn number', VALUE_OPTIONAL),
+                    'department'  => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL),
+                    'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL),
+                    'interests'   => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
+                    'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
+                    'lastaccess'  => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
+                    'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
+                    'descriptionformat' => new external_value(PARAM_INT, 'User profile description format', VALUE_OPTIONAL),
+                    'city'        => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
+                    'url'         => new external_value(PARAM_URL, 'URL of the user', VALUE_OPTIONAL),
+                    'country'     => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
+                    'profileimageurlsmall' => new external_value(PARAM_URL, 'User image profile URL - small version'),
+                    'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big version'),
+                    'customfields' => new external_multiple_structure(
+                        new external_single_structure(
+                            array(
+                                'type'  => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field - text field, checkbox...'),
+                                'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
+                                'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
+                                'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field - to be able to build the field class in the code'),
+                            )
+                        ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL),
+                    'groups' => new external_multiple_structure(
+                        new external_single_structure(
+                            array(
+                                'id'  => new external_value(PARAM_INT, 'group id'),
+                                'name' => new external_value(PARAM_RAW, 'group name'),
+                                'description' => new external_value(PARAM_RAW, 'group description'),
+                            )
+                        ), 'user groups', VALUE_OPTIONAL),
+                    'roles' => new external_multiple_structure(
+                        new external_single_structure(
+                            array(
+                                'roleid'       => new external_value(PARAM_INT, 'role id'),
+                                'name'         => new external_value(PARAM_RAW, 'role name'),
+                                'shortname'    => new external_value(PARAM_ALPHANUMEXT, 'role shortname'),
+                                'sortorder'    => new external_value(PARAM_INT, 'role sortorder')
+                            )
+                        ), 'user roles', VALUE_OPTIONAL),
+                    'preferences' => new external_multiple_structure(
+                        new external_single_structure(
+                            array(
+                                'name'  => new external_value(PARAM_ALPHANUMEXT, 'The name of the preferences'),
+                                'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
+                            )
+                    ), 'User preferences', VALUE_OPTIONAL),
+                    'enrolledcourses' => new external_multiple_structure(
+                        new external_single_structure(
+                            array(
+                                'id'  => new external_value(PARAM_INT, 'Id of the course'),
+                                'fullname' => new external_value(PARAM_RAW, 'Fullname of the course'),
+                                'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
+                            )
+                    ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
+                )
+            )
+        );
+    }
 
-            if ($user->url && (!isset($hiddenfields['webpage']) or $isadmin)) {
-                $url = $user->url;
-                if (strpos($user->url, '://') === false) {
-                    $url = 'http://'. $url;
-                }
-                $user->url = clean_param($user->url, PARAM_URL);
-                $userarray['url'] = $user->url;
-            }
+    /**
+     * Returns description of method parameters
+     * @return external_function_parameters
+     */
+    public static function get_users_by_courseid_parameters() {
+        return new external_function_parameters(
+            array(
+                'courseid' => new external_value(PARAM_INT, 'course id'),
+                'options'  => new external_multiple_structure(
+                    new external_single_structure(
+                        array(
+                            'name'  => new external_value(PARAM_ALPHANUMEXT, 'option name'),
+                            'value' => new external_value(PARAM_RAW, 'option value')
+                        )
+                    ), 'method options'),
+            )
+        );
+    }
 
-            if ($user->icq && (!isset($hiddenfields['icqnumber']) or $isadmin)) {
-                $userarray['icq'] = $user->icq;
-            }
+    /**
+     * Get course participants details
+     * @param int $courseid  course id
+     * @param array $options options {
+     *          'name' => option name
+     *          'value' => option value
+     * }
+     * @return array An array of users
+     */
+    public static function get_users_by_courseid($courseid, $options) {
+        global $CFG, $USER, $DB;
+        require_once($CFG->dirroot . "/user/lib.php");
 
-            if ($user->skype && (!isset($hiddenfields['skypeid']) or $isadmin)) {
-                $userarray['skype'] = $user->skype;
-            }
-            if ($user->yahoo && (!isset($hiddenfields['yahooid']) or $isadmin)) {
-                $userarray['yahoo'] = $user->yahoo;
-            }
-            if ($user->aim && (!isset($hiddenfields['aimid']) or $isadmin)) {
-                $userarray['aim'] = $user->aim;
-            }
-            if ($user->msn && (!isset($hiddenfields['msnid']) or $isadmin)) {
-                $userarray['msn'] = $user->msn;
+        $params = self::validate_parameters(
+            self::get_users_by_courseid_parameters(),
+            array(
+                'courseid'=>$courseid,
+                'options'=>$options
+            )
+        );
+        $withcapability = '';
+        $groupid        = 0;
+        $onlyactive     = false;
+        foreach ($options as $option) {
+            switch ($option['name']) {
+            case 'withcapability':
+                $withcapability = $option['value'];
+                break;
+            case 'groupid':
+                $groupid = (int)$option['value'];
+                break;
+            case 'onlyactive':
+                $onlyactive = !empty($option['value']);
+                break;
             }
+        }
 
-            if ((!isset($hiddenfields['firstaccess'])) or $isadmin) {
-                if ($user->firstaccess) {
-                    $userarray['firstaccess'] = $user->firstaccess;
-                } else {
-                    $userarray['firstaccess'] = 0;
-                }
-            }
-            if ((!isset($hiddenfields['lastaccess'])) or $isadmin) {
-                if ($user->lastaccess) {
-                    $userarray['lastaccess'] = $user->lastaccess;
-                } else {
-                    $userarray['lastaccess'] = 0;
-                }
-            }
-            /// Printing tagged interests
-            if (!empty($CFG->usetags)) {
-                require_once($CFG->dirroot . '/tag/lib.php');
-                if ($interests = tag_get_tags_csv('user', $user->id, TAG_RETURN_TEXT) ) {
-                    $userarray['interests'] = $interests;
-                }
-            }
+        // to overwrite this parameter, you need role:review capability
+        if ($withcapability) {
+            require_capability('moodle/role:review', $coursecontext);
+        }
+        // need accessallgroups capability if you want to overwrite this option
+        if (!empty($groupid) && groups_is_member($groupid)) {
+            require_capability('moodle/site:accessallgroups', $context);
+        }
+        // to overwrite this option, you need course:enrolereview permission
+        if ($onlyactive) {
+            require_capability('moodle/course:enrolreview', $coursecontext);
+        }
 
-            //Departement/Institution are not displayed on any profile, however you can get them from editing profile.
-            if ($isadmin or $currentuser) {
-                if ($user->institution) {
-                    $userarray['institution'] = $user->institution;
-                }
-                if (isset($user->department)) { //isset because it's ok to have department 0
-                    $userarray['department'] = $user->department;
-                }
-            }
+        list($coursectxselect, $coursectxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
+        $coursesql = "SELECT c.* $coursectxselect
+                        FROM {course} c $coursectxjoin
+                       WHERE c.id = $courseid";
+        $course = $DB->get_record_sql($coursesql);
+        context_instance_preload($course);
+        $coursecontext = get_context_instance(CONTEXT_COURSE, $params['courseid']);
+        if ($courseid == SITEID) {
+            $context = get_system_context();
+        } else {
+            $context = $coursecontext;
+        }
+        try {
+            self::validate_context($context);
+        } catch (Exception $e) {
+            $exceptionparam = new stdClass();
+            $exceptionparam->message = $e->getMessage();
+            $exceptionparam->courseid = $params['courseid'];
+            throw new moodle_exception(get_string('errorcoursecontextnotvalid' , 'webservice', $exceptionparam));
+        }
 
-            // not a big secret
-            $userarray['roles'] = array();
-            $roles = get_user_roles($context, $user->id, false);
-            foreach ($roles as $role) {
-                $userarray['roles'][] = array(
-                    'roleid'       => $role->roleid,
-                    'name'         => $role->name,
-                    'shortname'    => $role->shortname,
-                    'sortorder'    => $role->sortorder
-                );
+        list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive);
+        list($ctxselect, $ctxjoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx');
+        $records = $DB->get_records_sql($enrolledsql, $enrolledparams);
+        $sqlparams['courseid'] = $courseid;
+        $sql = "SELECT u.* $ctxselect
+                  FROM {user} u $ctxjoin
+                 WHERE u.id IN ($enrolledsql)
+                 ORDER BY u.id ASC";
+        $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams);
+        $users = array();
+        foreach ($enrolledusers as $user) {
+            if (!empty($user->deleted)) {
+                continue;
             }
-
-            // If groups are in use and enforced throughout the course, then make sure we can meet in at least one course level group
-            if (has_capability('moodle/site:accessallgroups', $context)) {
-                $usergroups = groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid, 'g.id, g.name,g.description');
-                foreach ($usergroups as $group) {
-                    $group->description = file_rewrite_pluginfile_urls($group->description, 'pluginfile.php', $context->id, 'group', 'description', $group->id);
-                    $userarray['groups'][] = array('id'=>$group->id, 'name'=>$group->name, 'description'=>$group->description);
-                }
+            context_instance_preload($user);
+            if ($userdetails = user_get_user_details($user, $course)) {
+                $users[] = $userdetails;
             }
-            $result[] = $userarray;
         }
+        $enrolledusers->close();
 
-        $users->close();
-
-        return $result;
+        return $users;
     }
-
     /**
      * Returns description of method result value
      * @return external_description
      */
-    public static function get_course_participants_by_id_returns() {
+    public static function get_users_by_courseid_returns() {
         return new external_multiple_structure(
             new external_single_structure(
                 array(
@@ -952,6 +795,21 @@ class moodle_user_external extends external_api {
                                 'sortorder'    => new external_value(PARAM_INT, 'role sortorder')
                             )
                         ), 'user roles', VALUE_OPTIONAL),
+                    'preferences' => new external_multiple_structure(
+                        new external_single_structure(
+                            array(
+                                'name'  => new external_value(PARAM_ALPHANUMEXT, 'The name of the preferences'),
+                                'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
+                            )
+                    ), 'User preferences', VALUE_OPTIONAL),
+                    'enrolledcourses' => new external_multiple_structure(
+                        new external_single_structure(
+                            array(
+                                'id'  => new external_value(PARAM_INT, 'Id of the course'),
+                                'fullname' => new external_value(PARAM_RAW, 'Fullname of the course'),
+                                'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
+                            )
+                    ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
                 )
             )
         );
index b5df18c..668e7a8 100644 (file)
@@ -96,13 +96,256 @@ function user_get_users_by_id($userids) {
     return $DB->get_records_list('user', 'id', $userids);
 }
 
+
+/**
+ *
+ * Give user record from mdl_user, build an array conntains
+ * all user details
+ * @param stdClass $user user record from mdl_user
+ * @param stdClass $context context object
+ * @param stdClass $course moodle course
+ * @return array
+ */
+function user_get_user_details($user, $course = null) {
+    global $USER, $DB, $CFG;
+    require_once($CFG->dirroot . "/user/profile/lib.php"); //custom field library
+    require_once($CFG->dirroot . "/lib/filelib.php");      // file handling on description and friends
+
+    if (!empty($course)) {
+        $context = get_context_instance(CONTEXT_COURSE, $course->id);
+        $usercontext = get_context_instance(CONTEXT_USER, $user->id);
+        $canviewdetailscap = has_capability('moodle/user:viewdetails', $usercontext);
+    } else {
+        $context = get_context_instance(CONTEXT_USER, $user->id);
+        $usercontext = $context;
+    }
+
+    $currentuser = ($user->id == $USER->id);
+    $isadmin = is_siteadmin($USER);
+
+    if (!empty($course)) {
+        $canviewhiddenuserfields = has_capability('moodle/course:viewhiddenuserfields', $context);
+    } else {
+        $canviewhiddenuserfields = has_capability('moodle/user:viewhiddendetails', $context);
+    }
+    $canviewdetailscap       = ($canviewdetailscap || has_capability('moodle/user:viewdetails', $context));
+    $canviewfullnames        = has_capability('moodle/site:viewfullnames', $context);
+    if (!empty($course)) {
+        $canviewuseremail = has_capability('moodle/course:useremail', $context);
+    } else {
+        $canviewuseremail = false;
+    }
+    $cannotviewdescription   = !empty($CFG->profilesforenrolledusersonly) && !$currentuser && !$DB->record_exists('role_assignments', array('userid'=>$user->id));
+    if (!empty($course)) {
+        $canaccessallgroups = has_capability('moodle/site:accessallgroups', $context);
+    } else {
+        $canaccessallgroups = false;
+    }
+
+    if (!$currentuser && !$canviewdetailscap && !has_coursecontact_role($user->id)) {
+        // skip this user details
+        return null;
+    }
+
+    $userdetails = array();
+    $userdetails['id'] = $user->id;
+
+    if ($isadmin or $currentuser) {
+        $userdetails['username'] = $user->username;
+    }
+    if ($isadmin or $canviewfullnames) {
+        $userdetails['firstname'] = $user->firstname;
+        $userdetails['lastname'] = $user->lastname;
+    }
+    $userdetails['fullname'] = fullname($user);
+
+    $fields = $DB->get_recordset_sql("SELECT f.*
+                                        FROM {user_info_field} f
+                                        JOIN {user_info_category} c
+                                             ON f.categoryid=c.id
+                                    ORDER BY c.sortorder ASC, f.sortorder ASC");
+    $userdetails['customfields'] = array();
+    foreach ($fields as $field) {
+        require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
+        $newfield = 'profile_field_'.$field->datatype;
+        $formfield = new $newfield($field->id, $user->id);
+        if ($formfield->is_visible() and !$formfield->is_empty()) {
+            $userdetails['customfields'][] =
+                array('name' => $formfield->field->name, 'value' => $formfield->data,
+                    'type' => $field->datatype, 'shortname' => $formfield->field->shortname);
+        }
+    }
+    $fields->close();
+    // unset customfields if it's empty
+    if (empty($userdetails['customfields'])) {
+        unset($userdetails['customfields']);
+    }
+
+    // profile image
+    $profileimageurl = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f1');
+    $userdetails['profileimageurl'] = $profileimageurl->out(false);
+    $profileimageurlsmall = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f2');
+    $userdetails['profileimageurlsmall'] = $profileimageurlsmall->out(false);
+
+    //hidden user field
+    if ($canviewhiddenuserfields) {
+        $hiddenfields = array();
+        // address, phone1 and phone2 not appears in hidden fields list
+        // but require viewhiddenfields capability
+        // according to user/profile.php
+        if ($user->address) {
+            $userdetails['address'] = $user->address;
+        }
+        if ($user->phone1) {
+            $userdetails['phone1'] = $user->phone1;
+        }
+        if ($user->phone2) {
+            $userdetails['phone2'] = $user->phone2;
+        }
+    } else {
+        $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
+    }
+
+    if (isset($user->description) && (!isset($hiddenfields['description']) or $isadmin)) {
+        if (!$cannotviewdescription) {
+            $user->description = file_rewrite_pluginfile_urls($user->description, 'pluginfile.php', $usercontext->id, 'user', 'profile', null);
+            $userdetails['description'] = $user->description;
+            $userdetails['descriptionformat'] = $user->descriptionformat;
+        }
+    }
+
+    if ((!isset($hiddenfields['country']) or $isadmin) && $user->country) {
+        $userdetails['country'] = $user->country;
+    }
+
+    if ((!isset($hiddenfields['city']) or $isadmin) && $user->city) {
+        $userdetails['city'] = $user->city;
+    }
+
+    if ($user->url && (!isset($hiddenfields['webpage']) or $isadmin)) {
+        $url = $user->url;
+        if (strpos($user->url, '://') === false) {
+            $url = 'http://'. $url;
+        }
+        $user->url = clean_param($user->url, PARAM_URL);
+        $userdetails['url'] = $user->url;
+    }
+
+    if ($user->icq && (!isset($hiddenfields['icqnumber']) or $isadmin)) {
+        $userdetails['icq'] = $user->icq;
+    }
+
+    if ($user->skype && (!isset($hiddenfields['skypeid']) or $isadmin)) {
+        $userdetails['skype'] = $user->skype;
+    }
+    if ($user->yahoo && (!isset($hiddenfields['yahooid']) or $isadmin)) {
+        $userdetails['yahoo'] = $user->yahoo;
+    }
+    if ($user->aim && (!isset($hiddenfields['aimid']) or $isadmin)) {
+        $userdetails['aim'] = $user->aim;
+    }
+    if ($user->msn && (!isset($hiddenfields['msnid']) or $isadmin)) {
+        $userdetails['msn'] = $user->msn;
+    }
+
+    if (!isset($hiddenfields['firstaccess']) or $isadmin) {
+        if ($user->firstaccess) {
+            $userdetails['firstaccess'] = $user->firstaccess;
+        } else {
+            $userdetails['firstaccess'] = 0;
+        }
+    }
+    if (!isset($hiddenfields['lastaccess']) or $isadmin) {
+        if ($user->lastaccess) {
+            $userdetails['lastaccess'] = $user->lastaccess;
+        } else {
+            $userdetails['lastaccess'] = 0;
+        }
+    }
+
+    if ($currentuser
+      or $canviewuseremail  // this is a capability in course context, it will be false in usercontext
+      or $user->maildisplay == 1
+      or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER))) {
+        $userdetails['email'] = $user->email;;
+    }
+
+    if (!empty($CFG->usetags)) {
+        require_once($CFG->dirroot . '/tag/lib.php');
+        if ($interests = tag_get_tags_csv('user', $user->id, TAG_RETURN_TEXT) ) {
+            $userdetails['interests'] = $interests;
+        }
+    }
+
+    //Departement/Institution are not displayed on any profile, however you can get them from editing profile.
+    if ($isadmin or $currentuser) {
+        if ($user->institution) {
+            $userdetails['institution'] = $user->institution;
+        }
+        if (isset($user->department)) { //isset because it's ok to have department 0
+            $userdetails['department'] = $user->department;
+        }
+    }
+
+    if (!empty($course)) {
+        // not a big secret
+        $roles = get_user_roles($context, $user->id, false);
+        $userdetails['roles'] = array();
+        foreach ($roles as $role) {
+            $userdetails['roles'][] = array(
+                'roleid'       => $role->roleid,
+                'name'         => $role->name,
+                'shortname'    => $role->shortname,
+                'sortorder'    => $role->sortorder
+            );
+        }
+    }
+
+    // If groups are in use and enforced throughout the course, then make sure we can meet in at least one course level group
+    if (!empty($course) && $canaccessallgroups) {
+        $usergroups = groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid, 'g.id, g.name,g.description');
+        $userdetails['groups'] = array();
+        foreach ($usergroups as $group) {
+            $group->description = file_rewrite_pluginfile_urls($group->description, 'pluginfile.php', $context->id, 'group', 'description', $group->id);
+            $userdetails['groups'][] = array('id'=>$group->id, 'name'=>$group->name, 'description'=>$group->description);
+        }
+    }
+    //list of courses where the user is enrolled
+    if (!isset($hiddenfields['mycourses'])) {
+        $enrolledcourses = array();
+        if ($mycourses = enrol_get_users_courses($user->id, true)) {
+            foreach ($mycourses as $mycourse) {
+                if ($mycourse->category) {
+                    $enrolledcourse = array();
+                    $enrolledcourse['id'] = $mycourse->id;
+                    $enrolledcourse['fullname'] = $mycourse->fullname;
+                    $enrolledcourse['shortname'] = $mycourse->shortname;
+                    $enrolledcourses[] = $enrolledcourse;
+                }
+            }
+            $userdetails['enrolledcourses'] = $enrolledcourses;
+        }
+    }
+
+    //user preferences
+    if ($currentuser) {
+        $preferences = array();
+        $userpreferences = get_user_preferences();
+         foreach($userpreferences as $prefname => $prefvalue) {
+            $preferences[] = array('name' => $prefname, 'value' => $prefvalue);
+         }
+         $userdetails['preferences'] = $preferences;
+    }
+    return $userdetails;
+}
+
 /**
  * Return a list of page types
  * @param string $pagetype current page type
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function user_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function user_page_type_list($pagetype, $parentcontext, $currentcontext) {
     return array(
         'user-profile'=>get_string('page-user-profile', 'pagetype'),
         'my-index'=>get_string('page-my-index', 'pagetype')
index 2504d70..fa70a8b 100644 (file)
@@ -31,7 +31,7 @@ defined('MOODLE_INTERNAL') || die();
 
 
 
-$version  = 2011062700.00;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2011062700.04;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes