Merge branch 'MDL-28949d' of git://github.com/srynot4sale/moodle
authorSam Hemelryk <sam@moodle.com>
Mon, 28 May 2012 20:49:29 +0000 (08:49 +1200)
committerSam Hemelryk <sam@moodle.com>
Mon, 28 May 2012 20:49:29 +0000 (08:49 +1200)
Conflicts:
lib/db/upgrade.php
version.php

23 files changed:
course/lib.php
grade/lib.php
lib/db/log.php
lib/db/upgrade.php
lib/filelib.php
lib/filestorage/file_storage.php
lib/gdlib.php
lib/moodlelib.php
lib/outputcomponents.php
lib/yui/dragdrop/dragdrop.js
mod/forum/rsslib.php
mod/forum/subscribe.php
pix/u/f3.png [new file with mode: 0644]
question/import_form.php
question/type/essay/db/upgrade.php
question/type/essay/renderer.php
question/type/essay/version.php
theme/boxxie/style/boilerplate.css [deleted file]
theme/serenity/layout/embedded.php [deleted file]
theme/serenity/layout/frontpage.php [deleted file]
theme/serenity/layout/general.php [deleted file]
theme/upgrade.txt
version.php

index 8e07373..648f87e 100644 (file)
@@ -2995,6 +2995,8 @@ function move_section($course, $section, $move) {
         }
         $n++;
     }
+    // After moving section, rebuild course cache.
+    rebuild_course_cache($course->id, true);
     return true;
 }
 
index e1937be..9d1bda9 100644 (file)
@@ -32,16 +32,56 @@ require_once $CFG->libdir.'/gradelib.php';
  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class graded_users_iterator {
-    public $course;
-    public $grade_items;
-    public $groupid;
-    public $users_rs;
-    public $grades_rs;
-    public $gradestack;
-    public $sortfield1;
-    public $sortorder1;
-    public $sortfield2;
-    public $sortorder2;
+
+    /**
+     * The couse whose users we are interested in
+     */
+    protected $course;
+
+    /**
+     * An array of grade items or null if only user data was requested
+     */
+    protected $grade_items;
+
+    /**
+     * The group ID we are interested in. 0 means all groups.
+     */
+    protected $groupid;
+
+    /**
+     * A recordset of graded users
+     */
+    protected $users_rs;
+
+    /**
+     * A recordset of user grades (grade_grade instances)
+     */
+    protected $grades_rs;
+
+    /**
+     * Array used when moving to next user while iterating through the grades recordset
+     */
+    protected $gradestack;
+
+    /**
+     * The first field of the users table by which the array of users will be sorted
+     */
+    protected $sortfield1;
+
+    /**
+     * Should sortfield1 be ASC or DESC
+     */
+    protected $sortorder1;
+
+    /**
+     * The second field of the users table by which the array of users will be sorted
+     */
+    protected $sortfield2;
+
+    /**
+     * Should sortfield2 be ASC or DESC
+     */
+    protected $sortorder2;
 
     /**
      * Should users whose enrolment has been suspended be ignored?
@@ -59,7 +99,7 @@ class graded_users_iterator {
      * @param string $sortfield2 The second field of the users table by which the array of users will be sorted
      * @param string $sortorder2 The order in which the second sorting field will be sorted (ASC or DESC)
      */
-    public function graded_users_iterator($course, $grade_items=null, $groupid=0,
+    public function __construct($course, $grade_items=null, $groupid=0,
                                           $sortfield1='lastname', $sortorder1='ASC',
                                           $sortfield2='firstname', $sortorder2='ASC') {
         $this->course      = $course;
@@ -75,6 +115,7 @@ class graded_users_iterator {
 
     /**
      * Initialise the iterator
+     *
      * @return boolean success
      */
     public function init() {
@@ -177,7 +218,7 @@ class graded_users_iterator {
      * Returns information about the next user
      * @return mixed array of user info, all grades and feedback or null when no more users found
      */
-    function next_user() {
+    public function next_user() {
         if (!$this->users_rs) {
             return false; // no users present
         }
@@ -244,10 +285,9 @@ class graded_users_iterator {
     }
 
     /**
-     * Close the iterator, do not forget to call this function.
-     * @return void
+     * Close the iterator, do not forget to call this function
      */
-    function close() {
+    public function close() {
         if ($this->users_rs) {
             $this->users_rs->close();
             $this->users_rs = null;
@@ -273,23 +313,23 @@ class graded_users_iterator {
 
 
     /**
-     * _push
+     * Add a grade_grade instance to the grade stack
      *
      * @param grade_grade $grade Grade object
      *
      * @return void
      */
-    function _push($grade) {
+    private function _push($grade) {
         array_push($this->gradestack, $grade);
     }
 
 
     /**
-     * _pop
+     * Remove a grade_grade instance from the grade stack
      *
-     * @return object current grade object
+     * @return grade_grade current grade object
      */
-    function _pop() {
+    private function _pop() {
         global $DB;
         if (empty($this->gradestack)) {
             if (empty($this->grades_rs) || !$this->grades_rs->valid()) {
index 16d1f43..f0475f6 100644 (file)
@@ -38,7 +38,7 @@ global $DB; // TODO: this is a hack, we should really do something with the SQL
 $logs = array(
     array('module'=>'course', 'action'=>'user report', 'mtable'=>'user', 'field'=>$DB->sql_concat('firstname', "' '" , 'lastname')),
     array('module'=>'course', 'action'=>'view', 'mtable'=>'course', 'field'=>'fullname'),
-    array('module'=>'course', 'action'=>'view section', 'mtable'=>'course_section', 'field'=>'COALESCE(name, section)'),
+    array('module'=>'course', 'action'=>'view section', 'mtable'=>'course_sections', 'field'=>'COALESCE(name, section)'),
     array('module'=>'course', 'action'=>'update', 'mtable'=>'course', 'field'=>'fullname'),
     array('module'=>'course', 'action'=>'enrol', 'mtable'=>'course', 'field'=>'fullname'), // there should be some way to store user id of the enrolled user!
     array('module'=>'course', 'action'=>'unenrol', 'mtable'=>'course', 'field'=>'fullname'), // there should be some way to store user id of the enrolled user!
index a2f0052..f505023 100644 (file)
@@ -648,11 +648,48 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012052100.00);
     }
 
+    if ($oldversion < 2012052500.03) { // fix invalid course_completion_records MDL-27368
+        //first get all instances of duplicate records
+        $sql = 'SELECT userid, course FROM {course_completions} WHERE (deleted IS NULL OR deleted <> 1) GROUP BY userid, course HAVING (count(id) > 1)';
+        $duplicates = $DB->get_recordset_sql($sql, array());
+
+        foreach ($duplicates as $duplicate) {
+            $pointer = 0;
+            //now get all the records for this user/course
+            $sql = 'userid = ? AND course = ? AND (deleted IS NULL OR deleted <> 1)';
+            $completions = $DB->get_records_select('course_completions', $sql,
+                array($duplicate->userid, $duplicate->course), 'timecompleted DESC, timestarted DESC');
+            $needsupdate = false;
+            $origcompletion = null;
+            foreach ($completions as $completion) {
+                $pointer++;
+                if ($pointer === 1) { //keep 1st record but delete all others.
+                    $origcompletion = $completion;
+                } else {
+                    //we need to keep the "oldest" of all these fields as the valid completion record.
+                    $fieldstocheck = array('timecompleted', 'timestarted', 'timeenrolled');
+                    foreach ($fieldstocheck as $f) {
+                        if ($origcompletion->$f > $completion->$f) {
+                            $origcompletion->$f = $completion->$f;
+                            $needsupdate = true;
+                        }
+                    }
+                    $DB->delete_records('course_completions', array('id'=>$completion->id));
+                }
+            }
+            if ($needsupdate) {
+                $DB->update_record('course_completions', $origcompletion);
+            }
+        }
+
+        // Main savepoint reached
+        upgrade_main_savepoint(true, 2012052500.03);
+    }
 
     /**
      * Major clean up of course completion tables
      */
-    if ($oldversion < 2012052500.02) {
+    if ($oldversion < 2012052900.00) {
 
         // Clean up all instances of duplicate records
         // Add indexes to prevent new duplicates
@@ -673,10 +710,10 @@ function xmldb_main_upgrade($oldversion) {
         }
 
         // Main savepoint reached
-        upgrade_main_savepoint(true, 2012052500.02);
+        upgrade_main_savepoint(true, 2012052900.00);
     }
 
-    if ($oldversion < 2012052500.03) {
+    if ($oldversion < 2012052900.01) {
 
         upgrade_course_completion_remove_duplicates(
             'course_completion_crit_compl',
@@ -695,10 +732,10 @@ function xmldb_main_upgrade($oldversion) {
         }
 
         // Main savepoint reached
-        upgrade_main_savepoint(true, 2012052500.03);
+        upgrade_main_savepoint(true, 2012052900.01);
     }
 
-    if ($oldversion < 2012052500.04) {
+    if ($oldversion < 2012052900.02) {
 
         upgrade_course_completion_remove_duplicates(
             'course_completion_aggr_methd',
@@ -715,8 +752,8 @@ function xmldb_main_upgrade($oldversion) {
         }
 
         // Main savepoint reached
-        upgrade_main_savepoint(true, 2012052500.04);
+        upgrade_main_savepoint(true, 2012052900.02);
     }
 
     return true;
-}
+}
\ No newline at end of file
index aa46e62..302ee9b 100644 (file)
@@ -3612,7 +3612,7 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null) {
             }
 
             // fix file name automatically
-            if ($filename !== 'f1' and $filename !== 'f2') {
+            if ($filename !== 'f1' and $filename !== 'f2' and $filename !== 'f3') {
                 $filename = 'f1';
             }
 
@@ -3625,20 +3625,28 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null) {
                 redirect($theme->pix_url('u/'.$filename, 'moodle')); // intentionally not cached
             }
 
-            if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.png')) {
-                if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.jpg')) {
-                    // bad reference - try to prevent future retries as hard as possible!
-                    if ($user = $DB->get_record('user', array('id'=>$context->instanceid), 'id, picture')) {
-                        if ($user->picture == 1 or $user->picture > 10) {
-                            $DB->set_field('user', 'picture', 0, array('id'=>$user->id));
+            if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'.png')) {
+                if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'.jpg')) {
+                    if ($filename === 'f3') {
+                        // f3 512x512px was introduced in 2.3, there might be only the smaller version.
+                        if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', 'f1.png')) {
+                            $file = $fs->get_file($context->id, 'user', 'icon', 0, '/', 'f1.jpg');
                         }
                     }
-                    // no redirect here because it is not cached
-                    $theme = theme_config::load($themename);
-                    $imagefile = $theme->resolve_image_location('u/'.$filename, 'moodle');
-                    send_file($imagefile, basename($imagefile), 60*60*24*14);
                 }
             }
+            if (!$file) {
+                // bad reference - try to prevent future retries as hard as possible!
+                if ($user = $DB->get_record('user', array('id'=>$context->instanceid), 'id, picture')) {
+                    if ($user->picture > 0) {
+                        $DB->set_field('user', 'picture', 0, array('id'=>$user->id));
+                    }
+                }
+                // no redirect here because it is not cached
+                $theme = theme_config::load($themename);
+                $imagefile = $theme->resolve_image_location('u/'.$filename, 'moodle');
+                send_file($imagefile, basename($imagefile), 60*60*24*14);
+            }
 
             send_stored_file($file, 60*60*24*365, 0, false, array('preview' => $preview)); // enable long caching, there are many images on each page
 
index 08013e0..9f0a3c2 100644 (file)
@@ -1028,7 +1028,7 @@ class file_storage {
 
         $newrecord->timecreated  = $filerecord->timecreated;
         $newrecord->timemodified = $filerecord->timemodified;
-        $newrecord->mimetype     = empty($filerecord->mimetype) ? $this->mimetype($pathname) : $filerecord->mimetype;
+        $newrecord->mimetype     = empty($filerecord->mimetype) ? $this->mimetype($pathname, $filerecord->filename) : $filerecord->mimetype;
         $newrecord->userid       = empty($filerecord->userid) ? null : $filerecord->userid;
         $newrecord->source       = empty($filerecord->source) ? null : $filerecord->source;
         $newrecord->author       = empty($filerecord->author) ? null : $filerecord->author;
@@ -1154,7 +1154,7 @@ class file_storage {
         list($newrecord->contenthash, $newrecord->filesize, $newfile) = $this->add_string_to_pool($content);
         $filepathname = $this->path_from_hash($newrecord->contenthash) . '/' . $newrecord->contenthash;
         // get mimetype by magic bytes
-        $newrecord->mimetype = empty($filerecord->mimetype) ? $this->mimetype($filepathname) : $filerecord->mimetype;
+        $newrecord->mimetype = empty($filerecord->mimetype) ? $this->mimetype($filepathname, $filerecord->filename) : $filerecord->mimetype;
 
         $newrecord->pathnamehash = $this->get_pathname_hash($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid, $newrecord->filepath, $newrecord->filename);
 
@@ -1805,11 +1805,15 @@ class file_storage {
      * If file has a known extension, we return the mimetype based on extension.
      * Otherwise (when possible) we try to get the mimetype from file contents.
      *
-     * @param string $pathname
+     * @param string $pathname full path to the file
+     * @param string $filename correct file name with extension, if omitted will be taken from $path
      * @return string
      */
-    public static function mimetype($pathname) {
-        $type = mimeinfo('type', $pathname);
+    public static function mimetype($pathname, $filename = null) {
+        if (empty($filename)) {
+            $filename = $pathname;
+        }
+        $type = mimeinfo('type', $filename);
         if ($type === 'document/unknown' && class_exists('finfo') && file_exists($pathname)) {
             $finfo = new finfo(FILEINFO_MIME_TYPE);
             $type = mimeinfo_from_type('type', $finfo->file($pathname));
index 68d891a..b4e4918 100644 (file)
@@ -119,6 +119,7 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
     $image->height = $imageinfo[1];
     $image->type   = $imageinfo[2];
 
+    $t = null;
     switch ($image->type) {
         case IMAGETYPE_GIF:
             if (function_exists('imagecreatefromgif')) {
@@ -127,6 +128,11 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
                 debugging('GIF not supported on this server');
                 return false;
             }
+            // Guess transparent colour from GIF.
+            $transparent = imagecolortransparent($im);
+            if ($transparent != -1) {
+                $t = imagecolorsforindex($im, $transparent);
+            }
             break;
         case IMAGETYPE_JPEG:
             if (function_exists('imagecreatefromjpeg')) {
@@ -166,19 +172,37 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
     if (function_exists('imagecreatetruecolor') and $CFG->gdversion >= 2) {
         $im1 = imagecreatetruecolor(100, 100);
         $im2 = imagecreatetruecolor(35, 35);
-        if ($image->type == IMAGETYPE_PNG and $imagefnc === 'imagepng') {
+        $im3 = imagecreatetruecolor(512, 512);
+        if ($image->type != IMAGETYPE_JPEG and $imagefnc === 'imagepng') {
+            if ($t) {
+                // Transparent GIF hacking...
+                $transparentcolour = imagecolorallocate($im1 , $t['red'] , $t['green'] , $t['blue']);
+                imagecolortransparent($im1 , $transparentcolour);
+                $transparentcolour = imagecolorallocate($im2 , $t['red'] , $t['green'] , $t['blue']);
+                imagecolortransparent($im2 , $transparentcolour);
+                $transparentcolour = imagecolorallocate($im3 , $t['red'] , $t['green'] , $t['blue']);
+                imagecolortransparent($im3 , $transparentcolour);
+            }
+
             imagealphablending($im1, false);
             $color = imagecolorallocatealpha($im1, 0, 0,  0, 127);
             imagefill($im1, 0, 0,  $color);
             imagesavealpha($im1, true);
+
             imagealphablending($im2, false);
             $color = imagecolorallocatealpha($im2, 0, 0,  0, 127);
             imagefill($im2, 0, 0,  $color);
             imagesavealpha($im2, true);
+
+            imagealphablending($im3, false);
+            $color = imagecolorallocatealpha($im3, 0, 0,  0, 127);
+            imagefill($im3, 0, 0,  $color);
+            imagesavealpha($im3, true);
         }
     } else {
         $im1 = imagecreate(100, 100);
         $im2 = imagecreate(35, 35);
+        $im3 = imagecreate(512, 512);
     }
 
     $cx = $image->width / 2;
@@ -192,6 +216,7 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
 
     imagecopybicubic($im1, $im, 0, 0, $cx - $half, $cy - $half, 100, 100, $half * 2, $half * 2);
     imagecopybicubic($im2, $im, 0, 0, $cx - $half, $cy - $half, 35, 35, $half * 2, $half * 2);
+    imagecopybicubic($im3, $im, 0, 0, $cx - $half, $cy - $half, 512, 512, $half * 2, $half * 2);
 
     $fs = get_file_storage();
 
@@ -220,6 +245,17 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
     $icon['filename'] = 'f2'.$imageext;
     $fs->create_file_from_string($icon, $data);
 
+    ob_start();
+    if (!$imagefnc($im3, NULL, $quality, $filters)) {
+        ob_end_clean();
+        $fs->delete_area_files($context->id, $component, $filearea, $itemid);
+        return false;
+    }
+    $data = ob_get_clean();
+    imagedestroy($im3);
+    $icon['filename'] = 'f3'.$imageext;
+    $fs->create_file_from_string($icon, $data);
+
     return $file1->get_id();
 }
 
index 8b0379b..23ee2f5 100644 (file)
@@ -9642,7 +9642,7 @@ function address_in_subnet($addr, $subnetstr) {
  */
 function mtrace($string, $eol="\n", $sleep=0) {
 
-    if (defined('STDOUT')) {
+    if (defined('STDOUT') and !PHPUNIT_TEST) {
         fwrite(STDOUT, $string.$eol);
     } else {
         echo $string . $eol;
index 514eac9..4bd0673 100644 (file)
@@ -321,6 +321,9 @@ class user_picture implements renderable {
         } else if ($this->size === true or $this->size == 1) {
             $filename = 'f1';
             $size = 100;
+        } else if ($this->size > 100) {
+            $filename = 'f3';
+            $size = (int)$this->size;
         } else if ($this->size >= 50) {
             $filename = 'f1';
             $size = (int)$this->size;
index 76cadf5..27d0f1d 100644 (file)
@@ -37,8 +37,7 @@ YUI.add('moodle-core-dragdrop', function(Y) {
                 .setAttrs({
                     'src' : M.util.image_url(MOVEICON.pix, MOVEICON.component),
                     'alt' : title,
-                    'title' : M.str.moodle.move,
-                    'hspace' : '3'
+                    'title' : M.str.moodle.move
                 });
             if (iconclass) {
                 dragicon.addClass(iconclass);
index f1444af..86bf31b 100644 (file)
@@ -31,7 +31,7 @@
  * @return string the full path to the cached RSS feed directory. Null if there is a problem.
  */
 function forum_rss_get_feed($context, $args) {
-    global $CFG, $DB;
+    global $CFG, $DB, $USER;
 
     $status = true;
 
@@ -43,7 +43,7 @@ function forum_rss_get_feed($context, $args) {
 
     $forumid  = clean_param($args[3], PARAM_INT);
     $cm = get_coursemodule_from_instance('forum', $forumid, 0, false, MUST_EXIST);
-    $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+    $modcontext = context_module::instance($cm->id);
 
     //context id from db should match the submitted one
     if ($context->id != $modcontext->id || !has_capability('mod/forum:viewdiscussion', $modcontext)) {
@@ -58,8 +58,14 @@ function forum_rss_get_feed($context, $args) {
     //the sql that will retreive the data for the feed and be hashed to get the cache filename
     $sql = forum_rss_get_sql($forum, $cm);
 
-    //hash the sql to get the cache file name
-    $filename = rss_get_file_name($forum, $sql);
+    // Hash the sql to get the cache file name.
+    // If the forum is Q and A then we need to cache the files per user. This can
+    // have a large impact on performance, so we want to only do it on this type of forum.
+    if ($forum->type == 'qanda') {
+        $filename = rss_get_file_name($forum, $sql . $USER->id);
+    } else {
+        $filename = rss_get_file_name($forum, $sql);
+    }
     $cachedfilepath = rss_get_file_full_name('mod_forum', $filename);
 
     //Is the cache out of date?
@@ -151,7 +157,7 @@ function forum_rss_feed_discussions_sql($forum, $cm, $newsince=0) {
     $now = round(time(), -2);
     $params = array($cm->instance);
 
-    $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+    $modcontext = context_module::instance($cm->id);
 
     if (!empty($CFG->forum_enabletimedposts)) { /// Users must fulfill timed posts
         if (!has_capability('mod/forum:viewhiddentimedposts', $modcontext)) {
@@ -205,7 +211,7 @@ function forum_rss_feed_discussions_sql($forum, $cm, $newsince=0) {
  * @return string the SQL query to be used to get the Post details from the forum table of the database
  */
 function forum_rss_feed_posts_sql($forum, $cm, $newsince=0) {
-    $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+    $modcontext = context_module::instance($cm->id);
 
     //get group enforcement SQL
     $groupmode    = groups_get_activity_groupmode($cm);
@@ -290,8 +296,10 @@ function forum_rss_get_group_sql($cm, $groupmode, $currentgroup, $modcontext=nul
  *
  * @Todo MDL-31129 implement post attachment handling
  */
-function forum_rss_feed_contents($forum, $sql, $context) {
-    global $CFG, $DB;
+
+function forum_rss_feed_contents($forum, $sql) {
+    global $CFG, $DB, $USER;
+
 
     $status = true;
 
@@ -305,23 +313,45 @@ function forum_rss_feed_contents($forum, $sql, $context) {
         $isdiscussion = false;
     }
 
+    if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
+        print_error('invalidcoursemodule');
+    }
+    $context = context_module::instance($cm->id);
+
     $formatoptions = new stdClass();
     $items = array();
     foreach ($recs as $rec) {
             $item = new stdClass();
             $user = new stdClass();
-            if ($isdiscussion && !empty($rec->discussionname)) {
-                $item->title = format_string($rec->discussionname);
-            } else if (!empty($rec->postsubject)) {
-                $item->title = format_string($rec->postsubject);
+
+            if ($isdiscussion && !forum_user_can_see_discussion($forum, $rec->discussionid, $context)) {
+                // This is a discussion which the user has no permission to view
+                $item->title = get_string('forumsubjecthidden', 'forum');
+                $message = get_string('forumbodyhidden', 'forum');
+                $item->author = get_string('forumauthorhidden', 'forum');
+            } else if (!$isdiscussion && !forum_user_can_see_post($forum, $rec->discussionid, $rec->postid, $USER, $cm)) {
+                // This is a post which the user has no permission to view
+                $item->title = get_string('forumsubjecthidden', 'forum');
+                $message = get_string('forumbodyhidden', 'forum');
+                $item->author = get_string('forumauthorhidden', 'forum');
             } else {
-                //we should have an item title by now but if we dont somehow then substitute something somewhat meaningful
-                $item->title = format_string($forum->name.' '.userdate($rec->postcreated,get_string('strftimedatetimeshort', 'langconfig')));
+                // The user must have permission to view
+                if ($isdiscussion && !empty($rec->discussionname)) {
+                    $item->title = format_string($rec->discussionname);
+                } else if (!empty($rec->postsubject)) {
+                    $item->title = format_string($rec->postsubject);
+                } else {
+                    //we should have an item title by now but if we dont somehow then substitute something somewhat meaningful
+                    $item->title = format_string($forum->name.' '.userdate($rec->postcreated,get_string('strftimedatetimeshort', 'langconfig')));
+                }
+                $user->firstname = $rec->userfirstname;
+                $user->lastname = $rec->userlastname;
+                $item->author = fullname($user);
+                $message = file_rewrite_pluginfile_urls($rec->postmessage, 'pluginfile.php', $context->id,
+                        'mod_forum', 'post', $rec->postid);
+                $formatoptions->trusted = $rec->posttrust;
             }
-            $user->firstname = $rec->userfirstname;
-            $user->lastname = $rec->userlastname;
-            $item->author = fullname($user);
-            $item->pubdate = $rec->postcreated;
+
             if ($isdiscussion) {
                 $item->link = $CFG->wwwroot."/mod/forum/discuss.php?d=".$rec->discussionid;
             } else {
@@ -329,8 +359,6 @@ function forum_rss_feed_contents($forum, $sql, $context) {
             }
 
             $formatoptions->trusted = $rec->posttrust;
-            $message = file_rewrite_pluginfile_urls($rec->postmessage, 'pluginfile.php', $context->id,
-                'mod_forum', 'post', $rec->postid);
             $item->description = format_text($message, $rec->postformat, $formatoptions, $forum->course);
 
             //TODO: MDL-31129 implement post attachment handling
@@ -342,6 +370,7 @@ function forum_rss_feed_contents($forum, $sql, $context) {
                     $item->attachments = array();
                 }
             }*/
+            $item->pubdate = $rec->postcreated;
 
             $items[] = $item;
         }
index 9066c8e..58a5fd5 100644 (file)
@@ -62,7 +62,7 @@ if ($user) {
     if (!has_capability('mod/forum:managesubscriptions', $context)) {
         print_error('nopermissiontosubscribe', 'forum');
     }
-    $user = $DB->get_record('user', array('id' => $user), MUST_EXIST);
+    $user = $DB->get_record('user', array('id' => $user), '*', MUST_EXIST);
 } else {
     $user = $USER;
 }
diff --git a/pix/u/f3.png b/pix/u/f3.png
new file mode 100644 (file)
index 0000000..27e3516
Binary files /dev/null and b/pix/u/f3.png differ
index 719317d..4a1a127 100644 (file)
@@ -122,6 +122,11 @@ class question_import_form extends moodleform {
             return $errors;
         }
 
+        if (empty($data['format'])) {
+            $errors['format'] = get_string('required');
+            return $errors;
+        }
+
         $formatfile = 'format/' . $data['format'] . '/format.php';
         if (!is_readable($formatfile)) {
             throw new moodle_exception('formatnotfound', 'question', '', $data['format']);
index 7a80f4d..6d60323 100644 (file)
@@ -40,5 +40,85 @@ function xmldb_qtype_essay_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    if ($oldversion < 2011102701) {
+        // In Moodle <= 2.0 essay had both question.generalfeedback and question_answers.feedback.
+        // This was silly, and in Moodel >= 2.1 only question.generalfeedback. To avoid
+        // dataloss, we concatenate question_answers.feedback onto the end of question.generalfeedback.
+        $toupdate = $DB->get_recordset_sql("
+                SELECT q.id,
+                       q.generalfeedback,
+                       q.generalfeedbackformat,
+                       qa.feedback,
+                       qa.feedbackformat
+
+                  FROM {question} q
+                  JOIN {question_answers} qa ON qa.question = q.id
+
+                 WHERE q.qtype = 'essay'
+                   AND " . $DB->sql_isnotempty('question_answers', 'feedback', false, true));
+
+        foreach ($toupdate as $data) {
+            upgrade_set_timeout(60);
+            if ($data->generalfeedbackformat == $data->feedbackformat) {
+                $DB->set_field('question', 'generalfeedback',
+                        $data->generalfeedback . $data->feedback,
+                        array('id' => $data->id));
+
+            } else {
+                $newdata = new stdClass();
+                $newdata->id = $data->id;
+                $newdata->generalfeedback =
+                        qtype_essay_convert_to_html($data->generalfeedback, $data->generalfeedbackformat) .
+                        qtype_essay_convert_to_html($data->feedback,        $data->feedbackformat);
+                $newdata->generalfeedbackformat = FORMAT_HTML;
+                $DB->update_record('question', $newdata);
+            }
+        }
+
+        $toupdate->close();
+
+        // Essay savepoint reached.
+        upgrade_plugin_savepoint(true, 2011102701, 'qtype', 'essay');
+    }
+
+    if ($oldversion < 2011102702) {
+        // Then we delete the old question_answers rows for essay questions.
+        $DB->delete_records_select('question_answers',
+                "question IN (SELECT id FROM {question} WHERE qtype = 'essay')");
+
+        // Essay savepoint reached.
+        upgrade_plugin_savepoint(true, 2011102702, 'qtype', 'essay');
+    }
+
     return true;
 }
+
+/**
+ * Convert some content to HTML.
+ * @param string $text the content to convert to HTML
+ * @param int $oldformat One of the FORMAT_... constants.
+ */
+function qtype_essay_convert_to_html($text, $oldformat) {
+    switch ($oldformat) {
+        // Similar to format_text.
+
+        case FORMAT_PLAIN:
+            $text = s($text);
+            $text = str_replace(' ', '&nbsp; ', $text);
+            $text = nl2br($text);
+            return $text;
+
+        case FORMAT_MARKDOWN:
+            return markdown_to_html($text);
+
+        case FORMAT_MOODLE:
+            return text_to_html($text);
+
+        case FORMAT_HTML:
+            return $text;
+
+        default:
+            throw new coding_exception(
+                    'Unexpected text format when upgrading essay questions.');
+    }
+}
index afb52f8..288954f 100644 (file)
@@ -113,7 +113,9 @@ class qtype_essay_renderer extends qtype_renderer {
         $pickeroptions->itemid = $qa->prepare_response_files_draft_itemid(
                 'attachments', $options->context->id);
 
-        return form_filemanager_render($pickeroptions) . html_writer::empty_tag(
+        $fm = new form_filemanager($pickeroptions);
+        $filesrenderer = $this->page->get_renderer('core', 'files');
+        return $filesrenderer->render($fm). html_writer::empty_tag(
                 'input', array('type' => 'hidden', 'name' => $qa->get_qt_field_name('attachments'),
                 'value' => $pickeroptions->itemid));
     }
index fec2889..0b44d4b 100644 (file)
@@ -26,7 +26,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 $plugin->component = 'qtype_essay';
-$plugin->version   = 2011102700;
+$plugin->version   = 2011102702;
 
 $plugin->requires  = 2011102700;
 
diff --git a/theme/boxxie/style/boilerplate.css b/theme/boxxie/style/boilerplate.css
deleted file mode 100644 (file)
index 3bf99fc..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/* -------------------------------------------------------------- 
-  
-   Boilerplate reset.css
-   * Resets default browser CSS.
-   
--------------------------------------------------------------- */
-
-html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; }
-body { line-height: 1.5; background: #fff; margin: 0; }
-table { border-collapse: collapse; border-spacing: 0; }
-caption, th, td { text-align: left; font-weight:400; }
-blockquote:before, blockquote:after, q:before, q:after { content: ""; }
-blockquote, q { quotes: "" ""; }
-a img { border: none; }
-input,textarea { margin: 0; }
-
-/* Removes Firefox imposed outline */
-a { outline: none; }
-
-/* Clearing floats without extra markup  */
-.wrapper { display: inline-block; }
-.wrapper:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
-* html .wrapper { height: 1%; }
-.wrapper { display: block; }
-
-/* -------------------------------------------------------------- 
-   
-   Boilerplate typography.css
-   * Sets up some sensible default typography.
-  
--------------------------------------------------------------- */
-
-/* This is where you set your desired font size. The line-heights 
-   and vertical margins are automatically calculated from this. 
-   The percentage is of 16px (0.75 * 16px = 12px). */
-body { font-size: 85%; }
-
-
-/* Default fonts and colors. */
-body,h1,h2,h3,h4,h5,h6,p,ul,ol,dl,input,textarea { font-family: Helvetica, Arial, sans-serif; }
-
-
-/* Headings
--------------------------------------------------------------- */
-
-h1,h2,h3,h4,h5,h6 { font-weight: bold; }
-
-h1 { font-size: 2.25em; line-height: 1; margin-bottom: 0.5em; }
-h2 { font-size: 1.75em; margin-bottom: 0.5em; }
-h3 { font-size: 1.5em; line-height: 1; margin-bottom: 1em; }
-h4 { font-size: 1.2em; line-height: 1.25; margin-bottom: 1em; }
-h5 { font-size: 1em; margin-bottom: 1.5em; }
-h6 { font-size: 1em; }
-
-
-/* Text elements
--------------------------------------------------------------- */
-
-p { margin: 0 0 1em; }
-
-ul, ol { margin: 0 1.5em 1.5em 1.5em; }
-ul { list-style-type: circle; }
-ol { list-style-type: decimal; }
-
-dl { margin: 0 0 1.5em 0; }
-dl dt { font-weight: bold; }
-dl dd { margin-left: 1.5em; }
-
-abbr, acronym { border-bottom: 1px dotted #000; }
-address { margin-top: 1.5em; font-style: italic; }
-del { color: #000; }
-
-a { color: #009; text-decoration: none; }
-a:hover { text-decoration: underline; }
-
-blockquote { margin: 1.5em; }
-strong { font-weight: bold; }
-em, dfn { font-style: italic; }
-dfn { font-weight: bold; }
-pre, code { margin: 1.5em 0; white-space: pre; }
-pre, code, tt { font: 1.2em monospace; line-height: 1.5; } 
-tt { display: block; margin: 1.5em 0; line-height: 1.5; }
-
-
-/* Tables
--------------------------------------------------------------- */
-
-th { border-bottom: 2px solid #ddd; font-weight: bold; }
-th,td { padding: 4px;vertical-align: middle }
-tfoot { font-style: italic; }
-caption { background: #ffc; }
-
-
-/* Some default classes
--------------------------------------------------------------- */
-
-.small { font-size: .8em; margin-bottom: 1.875em; line-height: 1.875em; }
-.large { font-size: 1.25em; line-height:1.5em; margin-bottom: 1em; }
-.quiet { color: #999; }
-
-.hide { display: none; }
-.highlight { background: #ffc; }
-
-.top { margin-top: 0; padding-top: 0; }
-.bottom { margin-bottom: 0; padding-bottom: 0; }
-
-/* -------------------------------------------------------------- 
-   
-   Boilerplate forms.css
-   * Sets up some default styling for forms
-   
--------------------------------------------------------------- */
-
-label { font-weight: bold; }
-
-/* Fieldsets */
-fieldset { padding: 1.4em; margin: 0 0 1.5em 0; border: 1px solid #ddd; }
-legend { padding: 0 .4em; font-weight: bold; font-size: 1.2em; }
-
-/* Textareas */
-textarea { margin: 0.5em 0.5em 0 0; }
-textarea { padding: .4em; }
-
-
-/* hForm
--------------------------------------------------------------- */
-form.hform p { margin: 0 0 .5em; }
-form.hform p label { float: left; width: 100px; }
-
-form.hform p input { width: 200px; }
-form.hform p select { width: 200px; }
-
-form.hform p input.button { width: auto; }
-form.hform p input.checkbox { width: auto; }
-form.hform p input.radio { width: auto; }
-
-form.hform p.checkbox { margin-left: 100px; }
-form.hform p.checkbox label { float: none; }
-form.hform p.checkbox input { width: auto; }
-
-
-/* vForm
--------------------------------------------------------------- */
-form.vform p { margin: 0 0 .5em; }
-form.vform p label { display: block; }
-
-form.vform p.checkbox label { display: inline; }
diff --git a/theme/serenity/layout/embedded.php b/theme/serenity/layout/embedded.php
deleted file mode 100644 (file)
index 9d39e02..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php echo $OUTPUT->doctype() ?>
-<html <?php echo $OUTPUT->htmlattributes() ?>>
-<head>
-    <title><?php echo $PAGE->title ?></title>
-    <link rel="shortcut icon" href="<?php echo $OUTPUT->pix_url('favicon', 'theme')?>" />
-    <?php echo $OUTPUT->standard_head_html() ?>
-</head>
-<body id="<?php p($PAGE->bodyid) ?>" class="<?php p($PAGE->bodyclasses) ?>">
-<?php echo $OUTPUT->standard_top_of_body_html() ?>
-
-<div id="page">
-
-<!-- END OF HEADER -->
-
-    <div id="content" class="clearfix">
-        <?php echo $OUTPUT->main_content() ?>
-    </div>
-
-<!-- START OF FOOTER -->
-</div>
-<?php echo $OUTPUT->standard_end_of_body_html() ?>
-</body>
-</html>
\ No newline at end of file
diff --git a/theme/serenity/layout/frontpage.php b/theme/serenity/layout/frontpage.php
deleted file mode 100644 (file)
index 3c21eaa..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-<?php
-
-$hassidepre = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-pre', $OUTPUT));
-$hassidepost = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-post', $OUTPUT));
-
-$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
-$showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT));
-$custommenu = $OUTPUT->custom_menu();
-$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
-
-$bodyclasses = array();
-if ($showsidepre && !$showsidepost) {
-    $bodyclasses[] = 'side-pre-only';
-} else if ($showsidepost && !$showsidepre) {
-    $bodyclasses[] = 'side-post-only';
-} else if (!$showsidepost && !$showsidepre) {
-    $bodyclasses[] = 'content-only';
-}
-if ($hassidepre || $hassidepost) {
-       $bodyclasses[] = 'background';
-}
-if ($hascustommenu) {
-    $bodyclasses[] = 'has_custom_menu';
-}
-
-echo $OUTPUT->doctype() ?>
-<html <?php echo $OUTPUT->htmlattributes() ?>>
-<head>
-    <title><?php echo $PAGE->title ?></title>
-    <link rel="shortcut icon" href="<?php echo $OUTPUT->pix_url('favicon', 'theme')?>" />
-    <meta name="description" content="<?php p(strip_tags(format_text($SITE->summary, FORMAT_HTML))) ?>" />
-    <?php echo $OUTPUT->standard_head_html() ?>
-</head>
-<body id="<?php p($PAGE->bodyid) ?>" class="<?php p($PAGE->bodyclasses.' '.join(' ', $bodyclasses)) ?>">
-<?php echo $OUTPUT->standard_top_of_body_html() ?>
-
-<div id="page">
-       <div id="wrapper" class="clearfix">
-
-<!-- START OF HEADER -->
-
-    <div id="page-header" class="clearfix">
-               <div id="page-header-wrapper">
-               <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
-           <div class="headermenu">
-                       <?php
-                           echo $OUTPUT->login_info();
-                       echo $OUTPUT->lang_menu();
-                           echo $PAGE->headingmenu;
-                       ?>
-               </div>
-           </div>
-    </div>
-<?php if ($hascustommenu) { ?>
-       <div id="custommenu"><?php echo $custommenu; ?></div>
-<?php } ?>
-<!-- END OF HEADER -->
-
-<!-- START OF CONTENT -->
-
-<div id="page-content-wrapper">
-    <div id="page-content">
-        <div id="region-main-box">
-            <div id="region-post-box">
-
-                <div id="region-main-wrap">
-                    <div id="region-main">
-                        <div class="region-content">
-                            <?php echo $OUTPUT->main_content() ?>
-                        </div>
-                    </div>
-                </div>
-
-                <?php if ($hassidepre) { ?>
-                <div id="region-pre" class="block-region">
-                    <div class="region-content">
-                        <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
-                    </div>
-                </div>
-                <?php } ?>
-
-                <?php if ($hassidepost) { ?>
-                <div id="region-post" class="block-region">
-                    <div class="region-content">
-                        <?php echo $OUTPUT->blocks_for_region('side-post') ?>
-                    </div>
-                </div>
-                <?php } ?>
-
-            </div>
-        </div>
-    </div>
-</div>
-
-<!-- END OF CONTENT -->
-
-       </div>
-
-<!-- START OF FOOTER -->
-
-    <div id="page-footer">
-        <p class="helplink">
-        <?php echo page_doc_link(get_string('moodledocslink')) ?>
-        </p>
-
-        <?php
-        echo $OUTPUT->login_info();
-        echo $OUTPUT->home_link();
-        echo $OUTPUT->standard_footer_html();
-        ?>
-    </div>
-
-<!-- END OF FOOTER -->
-</div>
-<?php echo $OUTPUT->standard_end_of_body_html() ?>
-</body>
-</html>
diff --git a/theme/serenity/layout/general.php b/theme/serenity/layout/general.php
deleted file mode 100644 (file)
index 3c454f3..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-<?php
-
-$hasheading = ($PAGE->heading);
-$hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
-$hasfooter = (empty($PAGE->layout_options['nofooter']));
-$hassidepre = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-pre', $OUTPUT));
-$hassidepost = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-post', $OUTPUT));
-
-$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
-$showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT));
-$custommenu = $OUTPUT->custom_menu();
-$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
-
-$bodyclasses = array();
-if ($showsidepre && !$showsidepost) {
-    $bodyclasses[] = 'side-pre-only';
-} else if ($showsidepost && !$showsidepre) {
-    $bodyclasses[] = 'side-post-only';
-} else if (!$showsidepost && !$showsidepre) {
-    $bodyclasses[] = 'content-only';
-}
-if ($hascustommenu) {
-    $bodyclasses[] = 'has_custom_menu';
-}
-echo $OUTPUT->doctype() ?>
-<html <?php echo $OUTPUT->htmlattributes() ?>>
-<head>
-    <title><?php echo $PAGE->title ?></title>
-    <link rel="shortcut icon" href="<?php echo $OUTPUT->pix_url('favicon', 'theme')?>" />
-    <?php echo $OUTPUT->standard_head_html() ?>
-</head>
-<body id="<?php p($PAGE->bodyid) ?>" class="<?php p($PAGE->bodyclasses.' '.join(' ', $bodyclasses)) ?>">
-<?php echo $OUTPUT->standard_top_of_body_html() ?>
-
-<div id="page">
-       <div id="wrapper" class="clearfix">
-<?php if ($hasheading || $hasnavbar) { ?>
-
-    <div id="page-header" class="clearfix">
-
-               <?php if ($hasheading) { ?>
-                       <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
-                   <div class="headermenu">
-                               <?php
-                               echo $OUTPUT->login_info();
-                                       if (!empty($PAGE->layout_options['langmenu'])) {
-                                       echo $OUTPUT->lang_menu();
-                                   }
-                               echo $PAGE->headingmenu
-                               ?>
-                       </div>
-               <?php } ?>
-
-    </div>
-
-       <?php if ($hascustommenu) { ?>
-       <div id="custommenu"><?php echo $custommenu; ?></div>
-       <?php } ?>
-
-    <?php if ($hasnavbar) { ?>
-           <div class="navbar clearfix">
-           <div class="breadcrumb"><?php echo $OUTPUT->navbar(); ?></div>
-            <div class="navbutton"> <?php echo $PAGE->button; ?></div>
-      </div>
-    <?php } ?>
-
-<?php } ?>
-
-<!-- END OF HEADER -->
-
-<div id="page-content-wrapper">
-    <div id="page-content">
-        <div id="region-main-box">
-            <div id="region-post-box">
-
-                <div id="region-main-wrap">
-                    <div id="region-main">
-                        <div class="region-content">
-                            <?php echo $OUTPUT->main_content() ?>
-                        </div>
-                    </div>
-                </div>
-
-                <?php if ($hassidepre) { ?>
-                <div id="region-pre" class="block-region">
-                    <div class="region-content">
-                        <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
-                    </div>
-                </div>
-                <?php } ?>
-
-                <?php if ($hassidepost) { ?>
-                <div id="region-post" class="block-region">
-                    <div class="region-content">
-                        <?php echo $OUTPUT->blocks_for_region('side-post') ?>
-                    </div>
-                </div>
-                <?php } ?>
-
-            </div>
-        </div>
-    </div>
-</div>
-
-    </div>
-
-<!-- START OF FOOTER -->
-    <?php if ($hasfooter) { ?>
-    <div id="page-footer" class="clearfix">
-        <p class="helplink"><?php echo page_doc_link(get_string('moodledocslink')) ?></p>
-        <?php
-        echo $OUTPUT->login_info();
-        echo $OUTPUT->home_link();
-        echo $OUTPUT->standard_footer_html();
-        ?>
-    </div>
-    <?php } ?>
-</div>
-<?php echo $OUTPUT->standard_end_of_body_html() ?>
-</body>
-</html>
index 4e9b5f1..4d18a33 100644 (file)
@@ -2,6 +2,11 @@ This files describes API changes in /theme/* themes,
 information provided here is intended especially for theme designer.
 
 
+=== 2.3 ===
+
+optional changes:
+* add new u/f3.png image when theme contains customised f1 and f2 default user images
+
 === 2.2 ===
 
 required changes:
index 6dc6b76..c7e462d 100644 (file)
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012052500.04;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012052900.02;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes