### Eclipse Workspace Patch 1.0
#P 19stable
Index: lang/en_utf8/forum.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lang/en_utf8/forum.php,v
retrieving revision 1.21.4.2
diff -u -r1.21.4.2 forum.php
--- lang/en_utf8/forum.php	19 Dec 2007 17:38:44 -0000	1.21.4.2
+++ lang/en_utf8/forum.php	15 Jan 2008 16:13:15 -0000
@@ -5,6 +5,13 @@
 $string['addanewquestion'] = 'Add a new question';
 $string['addanewtopic'] = 'Add a new topic';
 $string['advancedsearch'] = 'Advanced search';
+$string['aggregateavg'] = 'Average of ratings';
+$string['aggregatecount'] = 'Count of ratings';
+$string['aggregatemax'] = 'Maximum rating';
+$string['aggregatemin'] = 'Minimum rating';
+$string['aggregatenone'] = 'No ratings';
+$string['aggregatesum'] = 'Sum of ratings';
+$string['aggregatetype'] = 'Aggregate type';
 $string['allforums'] = 'All forums';
 $string['allowchoice'] = 'Allow everyone to choose';
 $string['allowdiscussions'] = 'Can a $a post to this forum?';
Index: mod/forum/rate.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/rate.php,v
retrieving revision 1.24
diff -u -r1.24 rate.php
--- mod/forum/rate.php	5 Jun 2007 22:58:39 -0000	1.24
+++ mod/forum/rate.php	15 Jan 2008 16:13:15 -0000
@@ -18,7 +18,9 @@
 
     if (!$cm = get_coursemodule_from_instance('forum', $forum->id)) {
         error("Course Module ID was incorrect");
-    }
+    } else {
+        $forum->cmidnumber = $cm->id; //MDL-12961
+        }
 
     require_login($course, false, $cm);
 
Index: mod/forum/lib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/lib.php,v
retrieving revision 1.609.2.14
diff -u -r1.609.2.14 lib.php
--- mod/forum/lib.php	11 Jan 2008 13:08:17 -0000	1.609.2.14
+++ mod/forum/lib.php	15 Jan 2008 16:13:15 -0000
@@ -19,6 +19,13 @@
 
 define('FORUM_UNSET_POST_RATING', -999);
 
+define ('FORUM_AGGREGATE_NONE', 0); //no ratings
+define ('FORUM_AGGREGATE_AVG', 1);
+define ('FORUM_AGGREGATE_COUNT', 2);
+define ('FORUM_AGGREGATE_MAX', 3);
+define ('FORUM_AGGREGATE_MIN', 4);
+define ('FORUM_AGGREGATE_SUM', 5);
+
 // this file may be included from some functions, we must define these as global explicitly
 global $FORUM_LAYOUT_MODES, $FORUM_TYPES, $FORUM_TYPES_ALL, $FORUM_OPEN_MODES;
 
@@ -109,7 +116,7 @@
 function forum_update_instance($forum) {
     $forum->timemodified = time();
     $forum->id           = $forum->instance;
-
+    $oldforum = get_record('forum', 'id', $forum->id);
     if (empty($forum->assessed)) {
         $forum->assessed = 0;
     }
@@ -119,6 +126,13 @@
         $forum->assesstimefinish = 0;
     }
 
+    // MDL-3942 - if the aggregation type or scale (i.e. max grade) changes then recalculate the grades for the entire forum
+    // if  scale changes - do we need to recheck the ratings, if ratings higher than scale how do we want to respond?
+    // for count and sum aggregation types the grade we check to make sure they do not exceed the scale (i.e. max score) when calculating the grade 
+    if (($oldforum->assessed<>$forum->assessed) or ($oldforum->scale<>$forum->scale)) { 
+        forum_update_grades($forum); // recalculate grades for the forum
+    }
+    
     if ($forum->type == 'single') {  // Update related discussion and post.
         if (! $discussion = get_record('forum_discussions', 'forum', $forum->id)) {
             if ($discussions = get_records('forum_discussions', 'forum', $forum->id, 'timemodified ASC')) {
@@ -1100,15 +1114,64 @@
 
     $user = $userid ? "AND u.id = $userid" : "";
 
+$aggtype = $forum->assessed;
+switch ($aggtype) {
+    case FORUM_AGGREGATE_COUNT :
+    $sql = "SELECT u.id, u.id AS userid, count(fr.rating) AS rawgrade
+                    FROM {$CFG->prefix}user u, {$CFG->prefix}forum_posts fp,
+                       {$CFG->prefix}forum_ratings fr, {$CFG->prefix}forum_discussions fd
+                    WHERE u.id = fp.userid AND fp.discussion = fd.id AND fr.post = fp.id
+                       AND fr.userid != u.id AND fd.forum = $forum->id
+                        $user
+                    GROUP BY u.id";
+                    break;
+    case FORUM_AGGREGATE_MAX :
+        $sql = "SELECT u.id, u.id AS userid, max(fr.rating) AS rawgrade
+                    FROM {$CFG->prefix}user u, {$CFG->prefix}forum_posts fp,
+                       {$CFG->prefix}forum_ratings fr, {$CFG->prefix}forum_discussions fd
+                    WHERE u.id = fp.userid AND fp.discussion = fd.id AND fr.post = fp.id
+                       AND fr.userid != u.id AND fd.forum = $forum->id
+                        $user
+                    GROUP BY u.id";
+                    break;
+    case FORUM_AGGREGATE_MIN :
+    $sql = "SELECT u.id, u.id AS userid, min(fr.rating) AS rawgrade
+                    FROM {$CFG->prefix}user u, {$CFG->prefix}forum_posts fp,
+                       {$CFG->prefix}forum_ratings fr, {$CFG->prefix}forum_discussions fd
+                    WHERE u.id = fp.userid AND fp.discussion = fd.id AND fr.post = fp.id
+                       AND fr.userid != u.id AND fd.forum = $forum->id
+                        $user
+                    GROUP BY u.id";
+                    break;
+    case FORUM_AGGREGATE_SUM :
+    $sql = "SELECT u.id, u.id AS userid, sum(fr.rating) AS rawgrade
+                    FROM {$CFG->prefix}user u, {$CFG->prefix}forum_posts fp,
+                       {$CFG->prefix}forum_ratings fr, {$CFG->prefix}forum_discussions fd
+                    WHERE u.id = fp.userid AND fp.discussion = fd.id AND fr.post = fp.id
+                       AND fr.userid != u.id AND fd.forum = $forum->id
+                        $user
+                    GROUP BY u.id";
+                    break;
+    default : //avg
     $sql = "SELECT u.id, u.id AS userid, avg(fr.rating) AS rawgrade
-              FROM {$CFG->prefix}user u, {$CFG->prefix}forum_posts fp,
-                   {$CFG->prefix}forum_ratings fr, {$CFG->prefix}forum_discussions fd
-             WHERE u.id = fp.userid AND fp.discussion = fd.id AND fr.post = fp.id
-                   AND fr.userid != u.id AND fd.forum = $forum->id
-                   $user
-          GROUP BY u.id";
-
-    return get_records_sql($sql);
+                    FROM {$CFG->prefix}user u, {$CFG->prefix}forum_posts fp,
+                       {$CFG->prefix}forum_ratings fr, {$CFG->prefix}forum_discussions fd
+                    WHERE u.id = fp.userid AND fp.discussion = fd.id AND fr.post = fp.id
+                       AND fr.userid != u.id AND fd.forum = $forum->id
+                        $user
+                    GROUP BY u.id";
+                    break;
+}
+
+    $results = get_records_sql($sql);
+    // it could throw off the grading if count and sum returned a rawgrade higher than scale
+    // so to prevent it we review the results and ensure that rawgrade does not exceed the scale, if it does we set rawgrade = scale (i.e. full credit) 
+    foreach ($results as $result) { 
+        if ($result->rawgrade >$forum->scale) {
+            $result->rawgrade = $forum->scale;
+        }
+    }
+   return $results;
 }
 
 /**
@@ -1119,7 +1182,7 @@
  */
 function forum_update_grades($forum=null, $userid=0, $nullifnone=true) {
     global $CFG;
-
+    
     if ($forum != null) {
         require_once($CFG->libdir.'/gradelib.php');
         if ($grades = forum_get_user_grades($forum, $userid)) {
@@ -2145,6 +2208,7 @@
             $discussion = get_record('forum_discussions', 'id', $post->discussion);
             $post->forum = $discussion->forum;
         }
+                 
         if (!$cm = get_coursemodule_from_instance('forum', $post->forum)) {
             error('Course Module ID was incorrect');
         }
@@ -2333,7 +2397,11 @@
     if (!isset($post->forumtype)) {
         $post->forumtype = get_field('forum', 'type', 'id', $post->forum);
     }
-
+    
+if (!isset($post->aggtype)) {
+        $post->aggtype = get_field('forum', 'assessed', 'id', $post->forum);
+    }
+    
     $age = time() - $post->created;
     // Hack for allow to edit news posts those are not displayed yet until they are displayed
     if (!$post->parent
@@ -2388,7 +2456,7 @@
             $canviewallratings = has_capability('mod/forum:viewanyrating', $post->modcontext);
 
             if ($canviewallratings and !$mypost) {
-                forum_print_ratings_mean($post->id, $ratings->scale, $canviewallratings);
+                forum_print_ratings_mean($post->id, $ratings->scale, $post->aggtype, $canviewallratings);
                 if (!empty($ratings->allow)) {
                     echo '&nbsp;';
                     forum_print_rating_menu($post->id, $USER->id, $ratings->scale);
@@ -2396,7 +2464,7 @@
                 }
 
             } else if ($mypost) {
-                forum_print_ratings_mean($post->id, $ratings->scale, true);
+                forum_print_ratings_mean($post->id, $ratings->scale, $post->aggtype, true);
 
             } else if (!empty($ratings->allow) ) {
                 forum_print_rating_menu($post->id, $USER->id, $ratings->scale);
@@ -2617,15 +2685,37 @@
 
 /**
  * Print the multiple ratings on a post given to the current user by others.
+ * Forumid prevents the double lookup of the forumid in discussion to determine the aggregate type
  * Scale is an array of ratings
  */
-function forum_print_ratings_mean($postid, $scale, $link=true) {
+function forum_print_ratings_mean($postid, $scale, $aggregatetype, $link=true) {
 
     static $strrate;
 
-    $mean = forum_get_ratings_mean($postid, $scale);
+    switch ($aggregatetype) {
+        case FORUM_AGGREGATE_AVG : 
+            $agg = forum_get_ratings_mean($postid, $scale);
+            $strratings = get_string("aggregateavg", "forum");
+            break;
+        case FORUM_AGGREGATE_COUNT : 
+            $agg = forum_get_ratings_count($postid, $scale);
+            $strratings = get_string("aggregatecount", "forum");
+            break;
+        case FORUM_AGGREGATE_MAX : 
+            $agg = forum_get_ratings_max($postid, $scale);
+            $strratings = get_string("aggregatemax", "forum");
+            break;
+        case FORUM_AGGREGATE_MIN : 
+            $agg = forum_get_ratings_min($postid, $scale);
+            $strratings = get_string("aggregatemin", "forum");
+            break;
+        case FORUM_AGGREGATE_SUM : 
+            $agg = forum_get_ratings_sum($postid, $scale);
+            $strratings = get_string("aggregatesum", "forum");
+            break;
+    }
 
-    if ($mean !== "") {
+    if ($agg !== "") {
 
         if (empty($strratings)) {
             $strratings = get_string("ratings", "forum");
@@ -2633,9 +2723,9 @@
 
         echo "$strratings: ";
         if ($link) {
-            link_to_popup_window ("/mod/forum/report.php?id=$postid", "ratings", $mean, 400, 600);
+            link_to_popup_window ("/mod/forum/report.php?id=$postid", "ratings", $agg, 400, 600);
         } else {
-            echo "$mean ";
+            echo "$agg ";
         }
     }
 }
@@ -2645,6 +2735,7 @@
  * Return the mean rating of a post given to the current user by others.
  * Scale is an array of possible ratings in the scale
  * Ratings is an optional simple array of actual ratings (just integers)
+ * Forumid is the forum id field needed - passing it avoids a double query of lookup up the discusion and then the forum id to get the aggregate type
  */
 function forum_get_ratings_mean($postid, $scale, $ratings=NULL) {
 
@@ -2659,7 +2750,7 @@
 
     $count = count($ratings);
 
-    if ($count == 0) {
+    if ($count == 0 ) {
         return "";
 
     } else if ($count == 1) {
@@ -2681,6 +2772,144 @@
 }
 
 /**
+ * Return the count of the ratings of a post given to the current user by others.
+ * Scale is an array of possible ratings in the scale - the end of the scale is the highest or max grade
+ * Ratings is an optional simple array of actual ratings (just integers)
+ */
+function forum_get_ratings_count($postid, $scale, $ratings=NULL) {
+
+    if (!$ratings) {
+        $ratings = array();
+        if ($rates = get_records("forum_ratings", "post", $postid)) {
+            foreach ($rates as $rate) {
+                $ratings[] = $rate->rating;
+            }
+        }
+    }
+
+    $count = count($ratings);
+    $scalecount = count($scale)-1; //this should give us the last element of the scale aka the max grade with  $scale[$scalecount]
+    
+    if ($count > $scale[$scalecount]) { //if the count exceeds the forum scale (i.e. max grade then set the score to the max grade
+        $count = $scale[$scalecount];
+    }
+    return $scale[$count];
+}
+
+/**
+ * Return the max rating of a post given to the current user by others.
+ * Scale is an array of possible ratings in the scale
+ * Ratings is an optional simple array of actual ratings (just integers)
+ */
+function forum_get_ratings_max($postid, $scale, $ratings=NULL) {
+
+    if (!$ratings) {
+        $ratings = array();
+        if ($rates = get_records("forum_ratings", "post", $postid)) {
+            foreach ($rates as $rate) {
+                $ratings[] = $rate->rating;
+            }
+        }
+    }
+
+    $count = count($ratings);
+    $max = max($ratings);
+
+    if ($count == 0 ) {
+        return "";
+
+    } else if ($count == 1) { //this works for max
+        return $scale[$ratings[0]];
+
+    } else {
+        
+     if (isset($scale[$max])) {
+            return $scale[$max]." ($count)";
+        } else {
+            return "$max ($count)";    // Should never happen, hopefully
+        }
+    }
+}
+
+/**
+ * Return the min rating of a post given to the current user by others.
+ * Scale is an array of possible ratings in the scale
+ * Ratings is an optional simple array of actual ratings (just integers)
+ */
+function forum_get_ratings_min($postid, $scale,  $ratings=NULL) {
+
+    if (!$ratings) {
+        $ratings = array();
+        if ($rates = get_records("forum_ratings", "post", $postid)) {
+            foreach ($rates as $rate) {
+                $ratings[] = $rate->rating;
+            }
+        }
+    }
+
+    $count = count($ratings);
+    $min = min($ratings);
+    
+    if ($count == 0 ) {
+        return "";
+
+    } else if ($count == 1) {
+        return $scale[$ratings[0]]; //this works for min
+
+    } else {
+        
+        if (isset($scale[$min])) {
+            return $scale[$min]." ($count)";
+        } else {
+            return "$min ($count)";    // Should never happen, hopefully
+        }
+    }
+}
+
+
+/**
+ * Return the sum or total of ratings of a post given to the current user by others.
+ * Scale is an array of possible ratings in the scale
+ * Ratings is an optional simple array of actual ratings (just integers)
+ */
+function forum_get_ratings_sum($postid, $scale, $ratings=NULL) {
+
+    if (!$ratings) {
+        $ratings = array();
+        if ($rates = get_records("forum_ratings", "post", $postid)) {
+            foreach ($rates as $rate) {
+                $ratings[] = $rate->rating;
+            }
+        }
+    }
+
+    $count = count($ratings);
+    $scalecount = count($scale)-1; //this should give us the last element of the scale aka the max grade with  $scale[$scalecount]
+    
+    if ($count == 0 ) {
+        return "";
+
+    } else if ($count == 1) { //this works for max.
+        return $scale[$ratings[0]];
+
+    } else {
+        $total = 0;
+        foreach ($ratings as $rating) {
+            $total += $rating;
+        }
+        if ($total > $scale[$scalecount]) { //if the total exceeds the max grade then set it to the max grade
+            $total = $scale[$scalecount];
+        } 
+        if (isset($scale[$total])) {
+            return $scale[$total]." ($count)";
+        } else {
+            return "$total ($count)";    // Should never happen, hopefully
+        }
+    }
+}
+
+
+/**
  * Return a summary of post ratings given to the current user by others.
  * Scale is an array of possible ratings in the scale
  * Ratings is an optional simple array of actual ratings (just integers)
@@ -5534,6 +5763,21 @@
     return true;
 }
 
+/**
+ * Returns array of forum aggregate types 
+ */
+function forum_get_aggregate_types() { 
 
+    $forum_aggregate_types   = array (
+        FORUM_AGGREGATE_NONE => get_string('aggregatenone', 'forum'),
+        FORUM_AGGREGATE_AVG    => get_string('aggregateavg', 'forum'),
+        FORUM_AGGREGATE_COUNT   => get_string('aggregatecount', 'forum'),
+        FORUM_AGGREGATE_MAX     => get_string('aggregatemax', 'forum'),
+        FORUM_AGGREGATE_MIN      => get_string('aggregatemin', 'forum'),
+        FORUM_AGGREGATE_SUM      => get_string('aggregatesum', 'forum'));
+
+return $forum_aggregate_types;
+
+}
 
 ?>
Index: mod/forum/mod_form.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/mod_form.php,v
retrieving revision 1.23.2.2
diff -u -r1.23.2.2 mod_form.php
--- mod/forum/mod_form.php	26 Nov 2007 04:42:24 -0000	1.23.2.2
+++ mod/forum/mod_form.php	15 Jan 2008 16:13:15 -0000
@@ -77,20 +77,23 @@
 
 //-------------------------------------------------------------------------------
         $mform->addElement('header', '', get_string('grade'));
-        $mform->addElement('checkbox', 'assessed', get_string('allowratings', 'forum') , get_string('ratingsuse', 'forum'));
-
+        
+        $mform->addElement('select', 'assessed', get_string('aggregatetype', 'forum') , forum_get_aggregate_types());
+        $mform->setDefault('assessed', 0);
+        $mform->setHelpButton('assessed', array('assessaggregate', get_string('aggregatetype', 'forum'), 'forum'));
+        
         $mform->addElement('modgrade', 'scale', get_string('grade'), false);
-        $mform->disabledIf('scale', 'assessed');
-
+        $mform->disabledIf('scale', 'assessed', 'eq', 0);
+        
         $mform->addElement('checkbox', 'ratingtime', get_string('ratingtime', 'forum'));
-        $mform->disabledIf('ratingtime', 'assessed');
+        $mform->disabledIf('ratingtime', 'assessed', 'eq', 0);
 
         $mform->addElement('date_time_selector', 'assesstimestart', get_string('from'));
-        $mform->disabledIf('assesstimestart', 'assessed');
+        $mform->disabledIf('assesstimestart', 'assessed', 'eq', 0);
         $mform->disabledIf('assesstimestart', 'ratingtime');
 
         $mform->addElement('date_time_selector', 'assesstimefinish', get_string('to'));
-        $mform->disabledIf('assesstimefinish', 'assessed');
+        $mform->disabledIf('assesstimefinish', 'assessed', 'eq', 0);
         $mform->disabledIf('assesstimefinish', 'ratingtime');
 
 
Index: lang/en_utf8/help/forum/assessaggregate.html
===================================================================
RCS file: lang/en_utf8/help/forum/assessaggregate.html
diff -N lang/en_utf8/help/forum/assessaggregate.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lang/en_utf8/help/forum/assessaggregate.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,17 @@
+<h1>Forum Aggregation Types</h1>
+
+<p>Forum aggregation defines how all the ratings given to posts in a forum are combined to form the final grade (for each post and for the whole forum activity).</p>
+
+<p>Choose from the following aggregation methods:</p>
+<ul>  
+<li>Average (default)
+<p>The mean of all the ratings given to posts in that forum. This is especially useful with peer grading when there are a lot of ratings being made.</p>
+ <li>Count
+<p>The number of rated posts becomes the final grade. This is useful when the number of posts is important. Note that the total can not exceed the maximum grade allowed for the forum.</p>
+<li>Max
+<p>The highest rating is returned as the final grade. This method is useful for emphasising the best work from participants, allowing them to post one high-quality post as well as a number of more casual responses to others.</p>
+<li>Min
+<p>The smallest rating is returned as the final grade. This method promotes a culture of high quality for all posts.</p>
+<li>Sum
+<p>All the ratings for a particular user are added together. Note that the total is not allowed to exceed the maximum grade for the forum.</p>
+</ul>

