### Eclipse Workspace Patch 1.0
#P 19stable
Index: mod/forum/post.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/post.php,v
retrieving revision 1.154.2.18
diff -u -r1.154.2.18 post.php
--- mod/forum/post.php	13 Oct 2009 20:53:57 -0000	1.154.2.18
+++ mod/forum/post.php	24 Apr 2010 15:27:05 -0000
@@ -7,6 +7,7 @@
 
     $reply   = optional_param('reply', 0, PARAM_INT);
     $forum   = optional_param('forum', 0, PARAM_INT);
+    $approve    = optional_param('approve', 0, PARAM_INT);
     $edit    = optional_param('edit', 0, PARAM_INT);
     $delete  = optional_param('delete', 0, PARAM_INT);
     $prune   = optional_param('prune', 0, PARAM_INT);
@@ -16,7 +17,7 @@
 
 
     //these page_params will be passed as hidden variables later in the form.
-    $page_params = array('reply'=>$reply, 'forum'=>$forum, 'edit'=>$edit);
+    $page_params = array('reply'=>$reply, 'forum'=>$forum, 'edit'=>$edit, 'approve'=>$approve);
 
     $sitecontext = get_context_instance(CONTEXT_SYSTEM);
 
@@ -77,8 +78,11 @@
         if (! $cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) {
             error("Incorrect course module");
         }
-
+        if (!$modcontext = get_context_instance(CONTEXT_MODULE, $cm->id)) {
+            error("Unable to get course module context");
+        }
         $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
+        $canapprove = forum_post_approved($forum);
 
         if (! forum_user_can_post_discussion($forum, $groupid, -1, $cm)) {
             if (has_capability('moodle/legacy:guest', $coursecontext, NULL, false)) {  // User is a guest here!
@@ -137,12 +141,15 @@
         if (! $cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) {
             error("Incorrect cm");
         }
+        if (!$modcontext = get_context_instance(CONTEXT_MODULE, $cm->id)) {
+            error("Unable to get course module context");
+        }
+        $canapprove = forum_post_approved($forum);
 
         // call course_setup to use forced language, MDL-6926 
         course_setup($course->id);
 
         $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
-        $modcontext    = get_context_instance(CONTEXT_MODULE, $cm->id);
 
         if (! forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext)) {
             if (has_capability('moodle/legacy:guest', $coursecontext, NULL, false)) {  // User is a guest here!
@@ -427,7 +434,32 @@
         }
         print_footer($course);
         die;
-    } else {
+    } 
+    else if (!empty($approve)) {  // User is approving a post - this is not yet working
+
+        if (! $post = forum_get_post_full($approve)) {
+            error("Post ID was incorrect");
+        }
+        if (! $discussion = get_record("forum_discussions", "id", $post->discussion)) {
+            error("This post is not part of a discussion! ($edit)");
+        }
+        if (! $forum = get_record("forum", "id", $discussion->forum)) {
+            error("The forum number was incorrect ($discussion->forum)");
+        }
+        if (! $course = get_record("course", "id", $discussion->course)) {
+            error("The course number was incorrect ($discussion->course)");
+        }
+        if (!$cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) {
+            error('Could not get the course module for the forum instance.');
+        } else {
+            $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+        }
+        if (has_capability('mod/forum:approvepost', $modcontext)) {
+            $post->approve = 1;
+        }
+        // update_record('forum_posts',$post);        
+    }    
+    else {
         error("No operation specified");
 
     }
@@ -532,6 +564,8 @@
             $message = '';
             $addpost=$fromform;
             $addpost->forum=$forum->id;
+            $addpost->approved = forum_post_approved($forum);
+ 
             if ($fromform->id = forum_add_new_post($addpost, $message)) {
 
                 $timemessage = 2;
@@ -723,7 +757,7 @@
         }
     }
 
-    if ($USER->id != $post->userid) {   // Not the original author, so add a message to the end
+    if (($USER->id != $post->userid) and (!$approve)){   // Not the original author, so add a message to the end
         $data->date = userdate($post->modified);
         if ($post->format == FORMAT_HTML) {
             $data->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$USER->id.'&course='.$post->course.'">'.
Index: mod/forum/rate_ajax.js
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/rate_ajax.js,v
retrieving revision 1.1.2.5
diff -u -r1.1.2.5 rate_ajax.js
--- mod/forum/rate_ajax.js	6 Apr 2009 03:44:13 -0000	1.1.2.5
+++ mod/forum/rate_ajax.js	24 Apr 2010 15:27:05 -0000
@@ -83,7 +83,14 @@
     };
 
     /** Here goes the request **/
-    var url = rate_ajax_config.wwwroot +  '/mod/forum/rate_ajax.php?postid=' + menu.name + '&rate=' + menu.value + '&sesskey=' + rate_ajax_config.sesskey;
+    var ratinginfo = new Array();
+    var ratingname = menu.name;
+    ratinginfo = ratingname.split('_');
+    var ratingtype = ratinginfo[1];
+    var ratingid = ratinginfo[0];
+    if (menu.namestatus != 'Ok') {
+    }
+    var url = rate_ajax_config.wwwroot +  '/mod/forum/rate_ajax.php?postid=' + ratingid + '&rate=' + menu.value + '&ratetype=' + ratingtype + '&sesskey=' + rate_ajax_config.sesskey;
     YAHOO.util.Connect.asyncRequest('GET', url, callback, null);
 
     /** Start animation **/
Index: mod/forum/rate.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/rate.php,v
retrieving revision 1.24.2.5
diff -u -r1.24.2.5 rate.php
--- mod/forum/rate.php	21 Nov 2009 15:33:34 -0000	1.24.2.5
+++ mod/forum/rate.php	24 Apr 2010 15:27:05 -0000
@@ -29,7 +29,7 @@
         error("Guests are not allowed to rate entries.");
     }
 
-    if (!$forum->assessed) {
+    if ((!$forum->assessed) and (!$forum->approve)) {
         error("Rating of items not allowed!");
     }
 
@@ -37,17 +37,31 @@
     require_capability('mod/forum:rate', $context);
 
     if ($data = data_submitted() and confirm_sesskey()) {
-
+        
         $discussionid = false;
 
     /// Calculate scale values
         $scale_values = make_grades_menu($forum->scale);
-
+      
         foreach ((array)$data as $postid => $rating) {
+            $ratingpos = strpos($postid,'_rating');
+            $approvedpos = strpos($postid,'_approved');
+            $ratingval=-1;
+            $approvedval=-1;
+            
+            if ($ratingpos) {
+                $postid = substr($postid,0,$ratingpos);
+                $ratingval = $rating;
+            } 
+            if ($approvedpos) {
+                $postid = substr($postid,0,$approvedpos);
+                $approvedval = $rating;
+            }
+            
             if (!is_numeric($postid)) {
                 continue;
             }
-
+            
             // following query validates the submitted postid too
             $sql = "SELECT fp.*
                       FROM {$CFG->prefix}forum_posts fp, {$CFG->prefix}forum_discussions fd
@@ -67,38 +81,52 @@
             }
 
         /// Check rate is valid for for that forum scale values
-            if (!array_key_exists($rating, $scale_values) && $rating != FORUM_UNSET_POST_RATING) {
-                print_error('invalidrate', 'forum', '', $rating);
-            }
+            if ($ratingpos) {
+                if (!array_key_exists($rating, $scale_values) && $rating != FORUM_UNSET_POST_RATING) {
+                    print_error('invalidrate', 'forum', '', $rating);
+                }
+            
+                if ($rating == FORUM_UNSET_POST_RATING) {
+                    delete_records('forum_ratings', 'post', $postid, 'userid', $USER->id);
+                    forum_update_grades($forum, $post->userid);
 
-            if ($rating == FORUM_UNSET_POST_RATING) {
-                delete_records('forum_ratings', 'post', $postid, 'userid', $USER->id);
-                forum_update_grades($forum, $post->userid);
-
-            } else if ($oldrating = get_record('forum_ratings', 'userid', $USER->id, 'post', $post->id)) {
-                if ($rating != $oldrating->rating) {
-                    $oldrating->rating = $rating;
-                    $oldrating->time   = time();
-                    if (! update_record('forum_ratings', $oldrating)) {
-                        error("Could not update an old rating ($post->id = $rating)");
+                } else if ($oldrating = get_record('forum_ratings', 'userid', $USER->id, 'post', $post->id)) {
+                    if ($rating != $oldrating->rating) {
+                        $oldrating->rating = $rating;
+                        $oldrating->time   = time();
+                        if (! update_record('forum_ratings', $oldrating)) {
+                            error("Could not update an old rating ($post->id = $rating)");
+                        }
+                        forum_update_grades($forum, $post->userid);
                     }
-                    forum_update_grades($forum, $post->userid);
-                }
 
-            } else {
-                $newrating = new object();
-                $newrating->userid = $USER->id;
-                $newrating->time   = time();
-                $newrating->post   = $post->id;
-                $newrating->rating = $rating;
+                } else {
+                    $newrating = new object();
+                    $newrating->userid = $USER->id;
+                    $newrating->time   = time();
+                    $newrating->post   = $post->id;
+                    $newrating->rating = $rating;
 
-                if (! insert_record('forum_ratings', $newrating)) {
-                    error("Could not insert a new rating ($postid = $rating)");
+                    if (! insert_record('forum_ratings', $newrating)) {
+                        error("Could not insert a new rating ($postid = $rating)");
+                    }
+                    forum_update_grades($forum, $post->userid);
+                }
+            }
+            
+            if ($approvedpos) {
+            
+                if ($post->approved != $rating) {
+                    $post->approved = $rating;
+                    $strapproved = ($post->approved == 1) ? get_string('approve','forum') : get_string('unapprove','forum');
+                    $discussionurl = "discuss.php?d=$post->discussion#p$post->id&parent=$post->id"; 
+                    add_to_log($course->id, "forum", "update post approval", "$discussionurl", $strapproved, $cm->id); 
+                    update_record('forum_posts',addslashes_recursive($post));
                 }
-                forum_update_grades($forum, $post->userid);
             }
         }
-
+        
+       
         if ($forum->type == 'single' or !$discussionid) {
             redirect("$CFG->wwwroot/mod/forum/view.php?id=$cm->id", get_string('ratingssaved', 'forum'));
         } else {
Index: mod/forum/lib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/lib.php,v
retrieving revision 1.609.2.100
diff -u -r1.609.2.100 lib.php
--- mod/forum/lib.php	23 Nov 2009 05:09:04 -0000	1.609.2.100
+++ mod/forum/lib.php	24 Apr 2010 15:27:05 -0000
@@ -26,6 +26,41 @@
 define ('FORUM_AGGREGATE_MIN', 4);
 define ('FORUM_AGGREGATE_SUM', 5);
 
+/// check for installation of patch
+global $CFG;
+$cfg_forum = get_config('patch/forum');
+
+
+    if (!isset($cfg_forum->version) or (!$cfg_forum->version=2009032200)) { // the patch has not been installed, modify tables and create capability
+        $result = true;
+        require_once($CFG->libdir.'/xmldb/classes/XMLDBConstants.php');
+        require_once($CFG->libdir.'/xmldb/classes/XMLDBObject.class.php');
+        require_once($CFG->libdir.'/xmldb/classes/XMLDBTable.class.php');
+        require_once($CFG->libdir.'/xmldb/classes/XMLDBField.class.php');
+        require_once($CFG->libdir.'/ddllib.php'); // Install/upgrade related db functions
+        
+        $table  = new XMLDBTable('forum');
+        $field = new XMLDBField('approve');
+        $field->setAttributes(XMLDB_TYPE_INTEGER, 2, TRUE, TRUE, null, null, null, 0, 'blockperiod');
+        
+        $table2  = new XMLDBTable('forum_posts');
+        $field2 = new XMLDBField('approved');
+        $field2->setAttributes(XMLDB_TYPE_INTEGER, 2, TRUE, TRUE, null, null, null, 0,'mailnow');
+        
+        $result = $result && add_field($table, $field);
+        $result = $result && add_field($table2, $field2);
+        $result = $result && update_capabilities('mod/forum');
+        
+        if (!$result) { // if something goes wrong
+            error($result);
+            die;
+        } else {
+            set_config('version',2009032200,'patch/forum');
+            echo 'Forum patch tables successfully installed';
+        }
+    }
+
+
 /// STANDARD FUNCTIONS ///////////////////////////////////////////////////////////
 
 /**
@@ -61,7 +96,7 @@
         $discussion->name     = $forum->name;
         $discussion->intro    = $forum->intro;
         $discussion->assessed = $forum->assessed;
-        $discussion->format   = $forum->type;
+        $discussion->format =  ($forum->approve) ? $discussion->format   = -1 : $discussion->format   = $forum->type;
         $discussion->mailnow  = false;
         $discussion->groupid  = -1;
 
@@ -1887,6 +1922,19 @@
 }
 
 /**
+ * Returns a list of ratings for all posts in discussion
+ * @param object $discussion
+ * @return array of ratings or false
+ */
+function forum_get_all_discussion_approvals($discussion) {
+    global $CFG;
+    return get_records_sql("SELECT p.id, p.userid, p.approved
+                              FROM {$CFG->prefix}forum_posts p
+                             WHERE p.discussion = $discussion->id
+                             ORDER BY p.id ASC");
+}
+
+/**
  * Returns a list of ratings for one specific user for all posts in discussion
  * @global object $CFG
  * @param object $discussions the discussions for which we return all ratings
@@ -1942,6 +1990,7 @@
  * @param int $starttime - posts created after this time
  * @param int $endtime - posts created before this
  * @param int $now - used for timed discussions only
+ * added p.approved to WHERE clause so that unapproved posts will not be mailed out
  */
 function forum_get_unmailed_posts($starttime, $endtime, $now=null) {
     global $CFG;
@@ -1960,6 +2009,7 @@
                                    JOIN {$CFG->prefix}forum_discussions d ON d.id = p.discussion
                              WHERE p.mailed = 0
                                    AND p.created >= $starttime
+                                   AND p.approved = 1
                                    AND (p.created < $endtime OR p.mailnow = 1)
                                    $timedsql
                           ORDER BY p.modified ASC");
@@ -2353,7 +2403,7 @@
         $forumsort = "d.timemodified DESC";
     }
     if (empty($fullpost)) {
-        $postdata = "p.id,p.subject,p.modified,p.discussion,p.userid";
+        $postdata = "p.id,p.subject,p.modified,p.discussion,p.userid,p.approved";
     } else {
         $postdata = "p.*";
     }
@@ -2794,7 +2844,7 @@
 
     global $USER, $CFG;
 
-    static $stredit, $strdelete, $strreply, $strparent, $strprune;
+    static $stredit, $strdelete, $strreply, $strparent, $strprune, $strapprove;
     static $strpruneheading, $displaymode;
     static $strmarkread, $strmarkunread;
 
@@ -2816,6 +2866,7 @@
         $cm->cache->caps['mod/forum:deleteownpost']    = has_capability('mod/forum:deleteownpost', $modcontext);
         $cm->cache->caps['mod/forum:deleteanypost']    = has_capability('mod/forum:deleteanypost', $modcontext);
         $cm->cache->caps['mod/forum:viewanyrating']    = has_capability('mod/forum:viewanyrating', $modcontext);
+        $cm->cache->caps['mod/forum:approvepost']    = has_capability('mod/forum:approvepost', $modcontext);
     }
 
     if (!isset($cm->uservisible)) {
@@ -2856,6 +2907,7 @@
         $stredit         = get_string('edit', 'forum');
         $strdelete       = get_string('delete', 'forum');
         $strreply        = get_string('reply', 'forum');
+        $strapprove    = get_string('approve','forum');
         $strparent       = get_string('parent', 'forum');
         $strpruneheading = get_string('pruneheading', 'forum');
         $strprune        = get_string('prune', 'forum');
@@ -2866,7 +2918,7 @@
     }
 
     $read_style = '';
-    // ignore trackign status if not tracked or tracked param missing
+    // ignore tracking status if not tracked or tracked param missing
     if ($istracked) {
         if (is_null($post_read)) {
             debugging('fetching post_read info');
@@ -3035,7 +3087,8 @@
     if ($reply) {
         $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?reply='.$post->id.'">'.$strreply.'</a>';
     }
-
+    
+    
     echo '<div class="commands">';
     echo implode(' | ', $commands);
     echo '</div>';
@@ -3044,6 +3097,7 @@
 // Ratings
 
     $ratingsmenuused = false;
+    $approvalmenuused = false;
     if (!empty($ratings) and isloggedin()) {
         echo '<div class="ratings">';
         $useratings = true;
@@ -3100,6 +3154,22 @@
         echo '</div>';
     }
 
+// Approval
+
+    
+    if (isloggedin()) {
+        echo '<div class="ratings">';
+        $mypost = ($USER->id == $post->userid);
+        $canapprove = $cm->cache->caps['mod/forum:approvepost'];
+        if ($canapprove && !$mypost && $forum->approve) { // if forum approvals and the user can approve and it is not their post
+                // echo '<span class="forumpostapprovaltext">' .
+                echo     forum_print_approval_menu($post->id, $post->userid, $post->approved);
+               //      '</span>';
+                     $approvalmenuused = true;
+            } 
+            echo '</div>'; 
+        }
+
 // Link to post if required
 
     if ($link) {
@@ -3123,7 +3193,7 @@
         forum_tp_mark_post_read($USER->id, $post, $forum->id);
     }
 
-    return $ratingsmenuused;
+    return ($ratingsmenuused or $approvalmenuused);
 }
 
 
@@ -3162,9 +3232,12 @@
     } else {
         $rowcount = ($rowcount + 1) % 2;
     }
-
-    $post->subject = format_string($post->subject,true);
-
+    $usercansee = forum_user_can_see_post($forum, $post->discussion, $post);
+    if ($post->approved || $usercansee) {
+        $post->subject = format_string($post->subject,true);
+    } else {
+        $post->subject = get_string('forumsubjecthidden','forum');
+    }
     echo "\n\n";
     echo '<tr class="discussion r'.$rowcount.'">';
 
@@ -3181,15 +3254,23 @@
     $postuser->imagealt = $post->imagealt;
     $postuser->picture = $post->picture;
 
-    echo '<td class="picture">';
-    print_user_picture($postuser, $forum->course);
-    echo "</td>\n";
-
-    // User name
-    $fullname = fullname($post, has_capability('moodle/site:viewfullnames', $modcontext));
-    echo '<td class="author">';
-    echo '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$post->userid.'&amp;course='.$forum->course.'">'.$fullname.'</a>';
-    echo "</td>\n";
+    if ($post->approved || $usercansee) {
+        echo '<td class="picture">';
+        print_user_picture($postuser, $forum->course);
+        echo "</td>\n";
+        // User name
+        $fullname = fullname($post, has_capability('moodle/site:viewfullnames', $modcontext));
+        echo '<td class="author">';
+        echo '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$post->userid.'&amp;course='.$forum->course.'">'.$fullname.'</a>';
+        echo "</td>\n";
+    } else {
+        echo '<td class="picture">';
+        echo "</td>\n";
+        echo '<td class="author">';
+        print_string('forumauthorhidden','forum');
+        echo "</td>\n";
+        
+    }
 
     // Group picture
     if ($group !== -1) {  // Groups are active - group is a group data object or NULL
@@ -3245,10 +3326,14 @@
     $usermodified->id        = $post->usermodified;
     $usermodified->firstname = $post->umfirstname;
     $usermodified->lastname  = $post->umlastname;
+    if ($post->approved || $usercansee) {
     echo '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$post->usermodified.'&amp;course='.$forum->course.'">'.
          fullname($usermodified).'</a><br />';
     echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.$parenturl.'">'.
           userdate($usedate, $datestring).'</a>';
+    } else {
+        echo  print_string('forumauthorhidden','forum');
+    }
     echo "</td>\n";
 
     echo "</tr>\n\n";
@@ -3619,6 +3704,22 @@
 }
 
 /**
+ * Print the menu of approval options 
+ * If the post has already been - set that value.
+ */
+function forum_print_approval_menu($postid, $userid, $approved) {
+
+    static $strapprove;
+    if (empty($strapprove)) {
+        $strapprove = get_string('approve', 'forum');
+    }
+    $options[0] = get_string('unapprove','forum');
+    $options[1] = get_string('approve','forum');
+    choose_from_menu($options, $postid.'_approved', $approved, '', '', $approved, false, false, 0, '', false, false, 'forumpostratingmenu');
+}
+
+
+/**
  * Print the menu of ratings as part of a larger form.
  * If the post has already been - set that value.
  * Scale is an array of ratings
@@ -3639,7 +3740,7 @@
         $strrate = get_string("rate", "forum");
     }
     $scale = array(FORUM_UNSET_POST_RATING => $strrate.'...') + $scale;
-    choose_from_menu($scale, $postid, $myrating, '', '', '0', false, false, 0, '', false, false, 'forumpostratingmenu');
+    choose_from_menu($scale, $postid.'_rating', $myrating, '', '', '0', false, false, 0, '', false, false, 'forumpostratingmenu');
 }
 
 /**
@@ -3941,8 +4042,13 @@
     global $USER, $CFG;
 
     $forum = get_record('forum', 'id', $post->forum);
-
+    if (!$cm = get_coursemodule_from_instance("forum", $forum->id, $forum->course)) {
+            error('Could not get the course module for the forum instance.');
+        }
+    $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+    
     $post->modified = time();
+    $post->approved = forum_post_approved($forum);
 
     $updatediscussion = new object();
     $updatediscussion->id           = $post->discussion;
@@ -4001,7 +4107,10 @@
     $post->course      = $forum->course; // speedup
     $post->format      = $discussion->format;
     $post->mailnow     = $discussion->mailnow;
+    $post_approved = forum_post_approved($forum);
+    $post->approved = $post_approved;
 
+    
     if (! $post->id = insert_record("forum_posts", $post) ) {
         return 0;
     }
@@ -4677,6 +4786,24 @@
             return false;
         }
     }
+    
+    if  ($post->userid<>$user->id) {
+        if (isset($cm->cache->caps['mod/forum:approvepost'])) {
+            if (!$cm->cache->caps['mod/forum:approvepost']) {
+                    if ($post->approved==0) {
+                        return false;
+                    }
+                }
+            } else {
+            $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+            if (!has_capability('mod/forum:approvepost', $modcontext, $user->id)) { 
+                if ($post->approved==0) {
+                    return false;
+                }
+            }
+        }
+    }
+
 
     if (isset($cm->uservisible)) {
         if (!$cm->uservisible) {
@@ -4938,7 +5065,6 @@
                 }
 
                 $discussion->forum = $forum->id;
-
                 forum_print_post($discussion, $discussion, $forum, $cm, $course, $ownpost, 0, $link, false);
             break;
         }
@@ -5021,40 +5147,51 @@
     $ratings = NULL;
     $ratingsmenuused = false;
     $ratingsformused = false;
-    if ($forum->assessed and isloggedin()) {
-        if ($scale = make_grades_menu($forum->scale)) {
-            $ratings =new object();
-            $ratings->scale = $scale;
-            $ratings->assesstimestart = $forum->assesstimestart;
-            $ratings->assesstimefinish = $forum->assesstimefinish;
-            $ratings->allow = $canrate;
-
-            if ($ratings->allow) {
-                echo '<form id="form" method="post" action="rate.php">';
-                echo '<div class="ratingform">';
-                echo '<input type="hidden" name="forumid" value="'.$forum->id.'" />';
-                echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
-                $ratingsformused = true;
-            }
-
-            // preload all ratings - one query only and minimal memory
-            $cm->cache->ratings = array();
-            $cm->cache->myratings = array();
-            if ($postratings = forum_get_all_discussion_ratings($discussion)) {
-                foreach ($postratings as $pr) {
-                    if (!isset($cm->cache->ratings[$pr->postid])) {
-                        $cm->cache->ratings[$pr->postid] = array();
-                    }
-                    $cm->cache->ratings[$pr->postid][$pr->id] = $pr->rating;
-                    if ($pr->userid == $USER->id) {
-                        $cm->cache->myratings[$pr->postid] = $pr->rating;
-                    }
-                }
-                unset($postratings);
-            }
-        }
-
-    }
+    if (($forum->assessed or $forum->approve) and isloggedin()) {
+        if ($forum->assessed) {
+            if ($scale = make_grades_menu($forum->scale)) {
+                $ratings =new object();
+                $ratings->scale = $scale;
+                $ratings->assesstimestart = $forum->assesstimestart;
+                $ratings->assesstimefinish = $forum->assesstimefinish;
+                $ratings->allow = $canrate;
+
+                // preload all ratings - one query only and minimal memory
+                $cm->cache->ratings = array();
+                $cm->cache->myratings = array();
+                if ($postratings = forum_get_all_discussion_ratings($discussion)) {
+                    foreach ($postratings as $pr) {
+                        if (!isset($cm->cache->ratings[$pr->postid])) {
+                            $cm->cache->ratings[$pr->postid] = array();
+                        } //end !isset
+                        $cm->cache->ratings[$pr->postid][$pr->id] = $pr->rating;
+                        if ($pr->userid == $USER->id) {
+                            $cm->cache->myratings[$pr->postid] = $pr->rating;
+                        } //end $pr->userid
+                    } //end foreach $postratings
+                    unset($postratings);
+                } //endif $postratings
+
+                // preload all approvals - not sure this really gets used but for starters I'll include it -ab
+                if ($postapprovals = forum_get_all_discussion_approvals($discussion)) { //get all approvals for discussion
+                    foreach ($postapprovals as $pa) {
+                        if (!isset($cm->cache->approved[$pa->id])) {
+                            $cm->cache->approved[$pa->id] = array();
+                        } //endif !isset
+                        $cm->cache->approved[$pa->id] = $pa->approved;
+                    } //end foreach $postapprovals
+                    unset($postapprovals);
+                } //endif $postapprovals
+            } //endif $scale
+        } //endif $forum->assessed
+        if ($forum->approve or $ratings->allow ) {
+            echo '<form id="form" method="post" action="rate.php">';
+            echo '<div class="ratingform">';
+            echo '<input type="hidden" name="forumid" value="'.$forum->id.'" />';
+            echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
+            $ratingsformused = true;
+        } //endif $forum->approve
+    } //endif $forum->assessed
 
     $post->forum = $forum->id;   // Add the forum id to the post object, later used by forum_print_post
     $post->forumtype = $forum->type;
@@ -5090,10 +5227,13 @@
             break;
     }
 
-    if ($ratingsformused) {
-        if ($ratingsmenuused) {
+            
+    if (($ratingsformused) or ($forum->approve)) { //if ratings and approve
+        if ($ratingsmenuused)  {
             echo '<div class="ratingsubmit">';
             echo '<input type="submit" id="forumpostratingsubmit" value="'.get_string('sendinratings', 'forum').'" />';
+            
+            
             if (ajaxenabled() && !empty($CFG->forum_ajaxrating)) { /// AJAX enabled, standard submission form
                 $rate_ajax_config_settings = array("pixpath"=>$CFG->pixpath, "wwwroot"=>$CFG->wwwroot, "sesskey"=>sesskey());
                 echo "<script type=\"text/javascript\">//<![CDATA[\n".
@@ -5108,7 +5248,6 @@
             }
             echo '</div>';
         }
-
         echo '</div>';
         echo '</form>';
     }
@@ -6392,7 +6531,7 @@
  *
  */
 function forum_get_post_actions() {
-    return array('add discussion','add post','delete discussion','delete post','move discussion','prune post','update post');
+    return array('add discussion','add post','delete discussion','delete post','move discussion','prune post','update post','approve post');
 }
 
 /**
@@ -6931,4 +7070,29 @@
     return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames', 'moodle/site:trustcontent');
 }
 
+/**
+ * Returns true if the post is approved by default (i.e. forum approval not required or the user has the capability to approve posts)
+ * @param $forum        - a forum object with the same attributes as a record from the forum database table
+ * @return boolean      - is the forum post approved
+ */
+function forum_post_approved($forum) {
+
+        if (! $cm = get_coursemodule_from_instance("forum", $forum->id, $forum->course)) {
+            error("Unable to get course module instance");
+        }
+        if (!$modcontext = get_context_instance(CONTEXT_MODULE, $cm->id)) {
+            error("Unable to get course module context");
+        }
+        $canapprove = has_capability('mod/forum:approvepost',$modcontext);
+
+    if ($forum->approve) { // if the forum requires approval
+                return $canapprove;
+            } else { // if the forum does not require approval then the post is automatically approved
+                return 1;
+            }
+}
+
+function forum_approve_post($post) {
+    
+}
 ?>
Index: mod/forum/rate_ajax.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/rate_ajax.php,v
retrieving revision 1.1.2.3
diff -u -r1.1.2.3 rate_ajax.php
--- mod/forum/rate_ajax.php	3 Jun 2009 19:59:16 -0000	1.1.2.3
+++ mod/forum/rate_ajax.php	24 Apr 2010 15:27:05 -0000
@@ -59,6 +59,7 @@
 /// Check required params
     $postid = required_param('postid', PARAM_INT); // The postid to rate
     $rate   = required_param('rate', PARAM_INT); // The rate to apply
+    $ratetype = required_param('ratetype', PARAM_ALPHA); //either rating or approved
 
 /// Check postid is valid
     if (!$post = get_record_sql("SELECT p.*,
@@ -87,7 +88,7 @@
     }
 
 /// Check forum can be rated
-    if (!$forum->assessed) {
+    if (!$forum->assessed && (!$forum->approve)) {
         print_error('norate', 'forum');
     }
 
@@ -95,63 +96,69 @@
     $context = get_context_instance(CONTEXT_MODULE, $cm->id);
     require_capability('mod/forum:rate', $context);
 
-/// Check timed ratings
-    if ($forum->assesstimestart and $forum->assesstimefinish) {
-        if ($post->created < $forum->assesstimestart or $post->created > $forum->assesstimefinish) {
-            // we can not rate this, ignore it - this should not happen anyway unless teacher changes setting
-            print_error('norate', 'forum');
-        }
-    }
-
-/// Calculate scale values
-    $scale_values = make_grades_menu($forum->scale);
-
-/// Check rate is valid for for that forum scale values
-    if (!array_key_exists($rate, $scale_values) && $rate != FORUM_UNSET_POST_RATING) {
-        print_error('invalidrate', 'forum');
-    }
-
-/// Everything ready, process rate
-
-/// Deleting rate
-    if ($rate == FORUM_UNSET_POST_RATING) {
-        delete_records('forum_ratings', 'post', $postid, 'userid', $USER->id);
-
-/// Updating rate
-    } else if ($oldrating = get_record('forum_ratings', 'userid', $USER->id, 'post', $post->id)) {
-        if ($rate != $oldrating->rating) {
-            $oldrating->rating = $rate;
-            $oldrating->time   = time();
-            if (!update_record('forum_ratings', $oldrating)) {
-                error("Could not update an old rating ($post->id = $rate)");
+    if ($ratetype == 'rating') {
+    /// Check timed ratings
+        if ($forum->assesstimestart and $forum->assesstimefinish) {
+            if ($post->created < $forum->assesstimestart or $post->created > $forum->assesstimefinish) {
+                // we can not rate this, ignore it - this should not happen anyway unless teacher changes setting
+                print_error('norate', 'forum');
             }
         }
+    /// Calculate scale values
+        $scale_values = make_grades_menu($forum->scale);
 
-/// Inserting rate
-    } else {
-        $newrating = new object();
-        $newrating->userid = $USER->id;
-        $newrating->time   = time();
-        $newrating->post   = $post->id;
-        $newrating->rating = $rate;
-
-        if (!insert_record('forum_ratings', $newrating)) {
-            print_error('cannotinsertrate', 'error', '', (object)array('id'=>$postid, 'rating'=>$rate));
-        }
-    }
-
-/// Update grades
+    /// Check rate is valid for for that forum scale values
+        if (!array_key_exists($rate, $scale_values) && $rate != FORUM_UNSET_POST_RATING) {
+            print_error('invalidrate', 'forum');
+        } //endif array_key_exists
+
+    /// Everything ready, process rate
+        if ($rate == FORUM_UNSET_POST_RATING) { /// Deleting rate
+            delete_records('forum_ratings', 'post', $postid, 'userid', $USER->id);
+        } else if ($oldrating = get_record('forum_ratings', 'userid', $USER->id, 'post', $post->id) and ($ratetype =='rating')) { /// Updating rate
+            if ($rate != $oldrating->rating) {
+                $oldrating->rating = $rate;
+                $oldrating->time   = time();
+                if (!update_record('forum_ratings', $oldrating)) {
+                    error("Could not update an old rating ($post->id = $rate)");
+                } //endif !update_record
+            } //endif $oldrating
+ 
+    /// Inserting rate
+        } else {
+            if ($ratetype=='rating') {
+                $newrating = new object();
+                $newrating->userid = $USER->id;
+                $newrating->time   = time();
+                $newrating->post   = $post->id;
+                $newrating->rating = $rate;
+
+                if (!insert_record('forum_ratings', $newrating)) {
+                    print_error('cannotinsertrate', 'error', '', (object)array('id'=>$postid, 'rating'=>$rate));
+                } //endif
+            } //endif
+        } //endelse
     forum_update_grades($forum, $post->userid);
-
+    } //end rating
 /// Check user can see any rate
     $canviewanyrating = has_capability('mod/forum:viewanyrating', $context);
 
 /// Decide if rates info is displayed
     $rateinfo = '';
-    if ($canviewanyrating) {
-        $rateinfo = forum_print_ratings($postid, $scale_values, $forum->assessed, true, NULL, true);
+    if ($canviewanyrating && ($ratetype == 'rating')) {
+            $rateinfo = forum_print_ratings($postid, $scale_values, $forum->assessed, true, NULL, true);
+    } //endif
+
+    if (($post->approved != $rate) && ($ratetype =='approved')) { //if approval status has changed
+        $post->approved = $rate;
+        $strapproved = ($post->approved == 1) ? get_string('approve','forum') : get_string('unapprove','forum');
+        $discussionurl = "discuss.php?d=$post->discussion#p$post->id&parent=$post->id"; 
+        add_to_log($course->id, "forum", "update post approval", "$discussionurl", $strapproved, $cm->id); 
+        if (!update_record('forum_posts',addslashes_recursive($post))) {
+            print_error('cannotupdateapproval', 'error', '', (object)array('id'=>$post->id, 'rating'=>$rate));
+        }
     }
-
+    
 /// Calculate response
     $response['status']  = 'Ok';
     $response['message'] = $rateinfo;
Index: mod/forum/mod_form.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/mod_form.php,v
retrieving revision 1.23.2.6
diff -u -r1.23.2.6 mod_form.php
--- mod/forum/mod_form.php	26 Jul 2008 15:17:05 -0000	1.23.2.6
+++ mod/forum/mod_form.php	24 Apr 2010 15:27:05 -0000
@@ -41,6 +41,14 @@
         $mform->setHelpButton('forcesubscribe', array('subscription2', get_string('forcesubscribeq', 'forum'), 'forum'));
 
         $options = array();
+        $options[0] = get_string('no');
+        $options[1] = get_string('yes');
+        $mform->addElement('select', 'approve', get_string('requireapprovalq', 'forum'), $options);
+        $mform->setHelpButton('approve', array('approve', get_string('requireapprovalq', 'forum'), 'forum'));
+        $mform->setDefault('approve',0);
+        
+
+        $options = array();
         $options[FORUM_TRACKING_OPTIONAL] = get_string('trackingoptional', 'forum');
         $options[FORUM_TRACKING_OFF] = get_string('trackingoff', 'forum');
         $options[FORUM_TRACKING_ON] = get_string('trackingon', 'forum');
Index: lang/en_utf8/forum.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lang/en_utf8/Attic/forum.php,v
retrieving revision 1.21.4.15
diff -u -r1.21.4.15 forum.php
--- lang/en_utf8/forum.php	30 Jan 2009 11:30:21 -0000	1.21.4.15
+++ lang/en_utf8/forum.php	24 Apr 2010 15:27:04 -0000
@@ -23,6 +23,8 @@
 $string['allsubscribe'] = 'Subscribe to all forums';
 $string['allunsubscribe'] = 'Unsubscribe from all forums';
 $string['anyfile'] = 'Any file';
+$string['approvalsaved'] = 'Approval saved';
+$string['approve'] = 'Approve';
 $string['attachment'] = 'Attachment';
 $string['blockafter'] = 'Post threshold for blocking';
 $string['blockperiod'] = 'Time period for blocking';
@@ -89,9 +91,10 @@
 $string['forcesubscribeq'] = 'Force everyone to be subscribed?';
 $string['forum'] = 'Forum';
 $string['forum:addnews'] = 'Add news';
+$string['forum:approvepost'] = 'Approve posts';
 $string['forumauthorhidden'] = 'Author (hidden)';
 $string['forumblockingalmosttoomanyposts'] = 'You are approaching the posting threshold. You have posted $a->numposts times in the last $a->blockperiod and the limit is $a->blockafter posts.';
-$string['forumbodyhidden'] = 'This post cannot be viewed by you, probably because you have not posted in the discussion yet.';
+$string['forumbodyhidden'] = 'This post cannot be viewed by you, probably because it has not yet been approved or you have not posted in the discussion.';
 $string['forum:createattachment'] = 'Create attachments';
 $string['forum:deleteanypost'] = 'Delete any posts (anytime)';
 $string['forum:deleteownpost'] = 'Delete own posts (within deadline)';
@@ -126,6 +129,7 @@
 $string['introsocial'] = 'An open forum for chatting about anything you want to';
 $string['introteacher'] = 'A forum for teacher-only notes and discussion';
 $string['invalidrate'] = 'Invalid rate ($a)';
+$string['invalidapproval'] = 'Invalid approval ($a)';
 $string['lastpost'] = 'Last post';
 $string['learningforums'] = 'Learning forums';
 $string['logblocked'] = 'Log blocked emails';
@@ -230,6 +234,7 @@
 $string['reply'] = 'Reply';
 $string['replyforum'] = 'Reply to forum';
 $string['replytouser'] = 'Use email address in reply';
+$string['requireapprovalq'] = 'Require approval?';
 $string['resetforumsall'] = 'Delete all posts';
 $string['resetforums'] = 'Delete posts from';
 $string['resetsubscriptions'] = 'Delete all forum subscriptions';
@@ -252,6 +257,7 @@
 $string['searchwhichforums'] = 'Choose which forums to search';
 $string['searchwords'] = 'These words can appear anywhere in the post';
 $string['seeallposts'] = 'See all posts made by this user';
+$string['sendinapprovals'] = 'Send in my latest approvals';
 $string['sendinratings'] = 'Send in my latest ratings';
 $string['shortpost'] = 'Short post';
 $string['showsubscribers'] = 'Show/edit current subscribers';
@@ -277,6 +283,7 @@
 $string['trackingon'] = 'On';
 $string['trackingoptional'] = 'Optional';
 $string['trackingtype'] = 'Read tracking for this forum?';
+$string['unapprove'] = 'Unapprove';
 $string['unread'] = 'Unread';
 $string['unreadposts'] = 'Unread posts';
 $string['unreadpostsnumber'] = '$a unread posts';
Index: lang/en_utf8/error.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lang/en_utf8/Attic/error.php,v
retrieving revision 1.26.2.25
diff -u -r1.26.2.25 error.php
--- lang/en_utf8/error.php	5 Oct 2009 17:43:43 -0000	1.26.2.25
+++ lang/en_utf8/error.php	24 Apr 2010 15:27:04 -0000
@@ -16,6 +16,8 @@
 $string['cannotsavemd5file'] = 'Cannot save md5 file';
 $string['cannotsavezipfile'] = 'Cannot save ZIP file';
 $string['cannotunzipfile'] = 'Cannot unzip file';
+$string['cannotupdateapproval'] = 'Could not update approval status ($a->id = $a->rating)';
+$string['cannotupdaterating'] = 'Could not update an old rating ($a->id = $a->rating)';
 $string['cannotupdaterecord'] = 'Could not update record ID $a';
 $string['cannotviewprofile'] = 'You cannot view the profile of this user';
 $string['cantunenrollfrommetacourse'] = 'You cannot unenrol from this meta course';
@@ -82,6 +84,7 @@
 $string['missingrequiredfield'] = 'A required field is missing';
 $string['modulemissingcode'] = 'Module $a is missing the code needed to perform this function';
 $string['modulerequirementsnotmet'] = 'Module \"$a->modulename\" ($a->moduleversion) could not be installed.  It requires a newer version of Moodle (currently you are using $a->currentmoodle, you need $a->requiremoodle).';
+$string['mustbeloggedin'] = 'You must be logged in to do this';
 $string['mustbeteacher'] = 'You must be a teacher to view this page';
 $string['nocategorydelete'] = 'Category \'$a\' cannot be deleted!';
 $string['nocontext'] = 'Sorry, but that course is not a valid context';
Index: mod/forum/db/access.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/db/access.php,v
retrieving revision 1.15.2.1
diff -u -r1.15.2.1 access.php
--- mod/forum/db/access.php	23 Jul 2008 16:09:14 -0000	1.15.2.1
+++ mod/forum/db/access.php	24 Apr 2010 15:27:05 -0000
@@ -182,6 +182,50 @@
         )
     ),
 
+    'mod/forum:approvepost' => array(
+
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_MODULE,
+        'legacy' => array(
+            'teacher' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW,
+            'admin' => CAP_ALLOW
+        )
+    ),
+    
+    'mod/forum:approvepost' => array(
+
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_MODULE,
+        'legacy' => array(
+            'teacher' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW,
+            'admin' => CAP_ALLOW
+        )
+    ),
+    
+    'mod/forum:approvepost' => array(
+
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_MODULE,
+        'legacy' => array(
+            'teacher' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW,
+            'admin' => CAP_ALLOW
+        )
+    ),
+    
+    'mod/forum:approvepost' => array(
+
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_MODULE,
+        'legacy' => array(
+            'teacher' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW,
+            'admin' => CAP_ALLOW
+        )
+    ),
+    
     'mod/forum:splitdiscussions' => array(
 
         'captype' => 'read',
Index: mod/forum/patch_forum_approveposts.txt
===================================================================
RCS file: mod/forum/patch_forum_approveposts.txt
diff -N mod/forum/patch_forum_approveposts.txt
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mod/forum/patch_forum_approveposts.txt	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,22 @@
+This file serves as a README.txt file for the Forum Approve Posts patch contributed by Anthony Borrow (anthony@moodle.org).
+
+DESCRIPTION - The Forum Approve Posts patch is designed to enable the ability for a teacher or other user with the mod/forum:approvepost capability to approve posts before they are visible to other users or emailed to subscribers. 
+
+USAGE 
+
+1) When creating the forum, the teacher indicates that the forum will require approval.
+2) The teacher then reviews the forums and clicks on the Approve link to approve individual posts.
+
+INSTALLATION
+
+1) Apply the patch file to your Moodle installation (see http://docs.moodle.org/en/Development:How_to_apply_a_patch)
+2) Login as the system adminstrator and go to any page that requires the /mod/forum/lib.php file
+3) The modified /mod/forum/lib.php file will check to see if the patch has been installed and if not it will begin to add the approve field to the forum table and the approved field to the forum_post table and create the mod/forum:approvepost capability. After installation, a message indicating that the patch has been successfully installed will be displayed.
+
+TODO
+
+This patch is currently being developed in response to http://tracker.moodle.org/browse/CONTRIB-1085. Please create new issues in the tracker for any suggestions, bug reports, improvements, etc. 
+
+KNOWN ISSUES
+
+For a listing of current issues with the patch please see: http://tracker.moodle.org/browse/CONTRIB/component/10440
\ No newline at end of file
