### Eclipse Workspace Patch 1.0
#P contrib-1085
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	5 Apr 2009 04:15:06 -0000
@@ -182,6 +182,17 @@
         )
     ),
 
+    '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/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	5 Apr 2009 04:15:06 -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: mod/forum/post.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/post.php,v
retrieving revision 1.154.2.17
diff -u -r1.154.2.17 post.php
--- mod/forum/post.php	14 Jan 2009 04:55:10 -0000	1.154.2.17
+++ mod/forum/post.php	5 Apr 2009 04:15:06 -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/lib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/lib.php,v
retrieving revision 1.609.2.90
diff -u -r1.609.2.90 lib.php
--- mod/forum/lib.php	20 Mar 2009 13:38:27 -0000	1.609.2.90
+++ mod/forum/lib.php	5 Apr 2009 04:15: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;
 
@@ -1857,6 +1892,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
@@ -1912,6 +1960,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;
@@ -1930,6 +1979,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");
@@ -2764,7 +2814,7 @@
 
     global $USER, $CFG;
 
-    static $stredit, $strdelete, $strreply, $strparent, $strprune;
+    static $stredit, $strdelete, $strreply, $strparent, $strprune, $strapprove;
     static $strpruneheading, $displaymode;
     static $strmarkread, $strmarkunread;
 
@@ -2786,6 +2836,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)) {
@@ -2826,6 +2877,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');
@@ -2836,7 +2888,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');
@@ -3005,7 +3057,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>';
@@ -3014,6 +3067,7 @@
 // Ratings
 
     $ratingsmenuused = false;
+    $approvalmenuused = false;
     if (!empty($ratings) and isloggedin()) {
         echo '<div class="ratings">';
         $useratings = true;
@@ -3070,6 +3124,22 @@
         echo '</div>';
     }
 
+// Approval
+
+    
+    if (isloggedin()) {
+        echo '<div class="approvals">';
+        $mypost = ($USER->id == $post->userid);
+        $canapprove = $cm->cache->caps['mod/forum:approvepost'];
+        if ($canapprove and !$mypost) {
+                // 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) {
@@ -3093,7 +3163,7 @@
         forum_tp_mark_post_read($USER->id, $post, $forum->id);
     }
 
-    return $ratingsmenuused;
+    return ($ratingsmenuused or $approvalmenuused);
 }
 
 
@@ -3582,6 +3652,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, 'forumpostapprovalmenu');
+}
+
+
+/**
  * 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
@@ -3602,7 +3688,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');
 }
 
 /**
@@ -3899,8 +3985,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;
@@ -3959,7 +4050,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;
     }
@@ -4592,20 +4686,20 @@
 
     // retrieve objects (yuk)
     if (is_numeric($forum)) {
-        debugging('missinf full forum', DEBUG_DEVELOPER);
+        debugging('missing full forum', DEBUG_DEVELOPER);
         if (!$forum = get_record('forum','id',$forum)) {
             return false;
         }
     }
 
     if (is_numeric($discussion)) {
-        debugging('missinf full discussion', DEBUG_DEVELOPER);
+        debugging('missing full discussion', DEBUG_DEVELOPER);
         if (!$discussion = get_record('forum_discussions','id',$discussion)) {
             return false;
         }
     }
     if (is_numeric($post)) {
-        debugging('missinf full post', DEBUG_DEVELOPER);
+        debugging('missing full post', DEBUG_DEVELOPER);
         if (!$post = get_record('forum_posts','id',$post)) {
             return false;
         }
@@ -4635,6 +4729,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) {
@@ -4979,38 +5091,49 @@
     $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.'" />';
-                $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();
+    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();
+                        }
+                        $cm->cache->ratings[$pr->postid][$pr->id] = $pr->rating;
+                        if ($pr->userid == $USER->id) {
+                            $cm->cache->myratings[$pr->postid] = $pr->rating;
+                        }
                     }
-                    $cm->cache->ratings[$pr->postid][$pr->id] = $pr->rating;
-                    if ($pr->userid == $USER->id) {
-                        $cm->cache->myratings[$pr->postid] = $pr->rating;
+                    unset($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();
+                        }
+                        $cm->cache->approved[$pa->id] = $pa->approved;
                     }
+                    unset($postapprovals);
                 }
-                unset($postratings);
             }
         }
-
+        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.'" />';
+            $ratingsformused = true;
+        }
     }
 
     $post->forum = $forum->id;   // Add the forum id to the post object, later used by forum_print_post
@@ -5047,10 +5170,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".
@@ -5065,7 +5191,6 @@
             }
             echo '</div>';
         }
-
         echo '</div>';
         echo '</form>';
     }
@@ -6349,7 +6474,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');
 }
 
 /**
@@ -6888,4 +7013,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.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/rate.php,v
retrieving revision 1.24.2.4
diff -u -r1.24.2.4 rate.php
--- mod/forum/rate.php	27 Jan 2009 18:08:29 -0000	1.24.2.4
+++ mod/forum/rate.php	5 Apr 2009 04:15:06 -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()) {
-
+        
         $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',$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/rate_ajax.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/forum/rate_ajax.php,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 rate_ajax.php
--- mod/forum/rate_ajax.php	17 Jan 2009 19:30:08 -0000	1.1.2.2
+++ mod/forum/rate_ajax.php	5 Apr 2009 04:15:06 -0000
@@ -46,7 +46,7 @@
 
 /// Check access.
     if (!isloggedin()) {
-        print_error('mustbeloggedin');
+        print_error('loggedinnot');
     }
     if (isguestuser()) {
         print_error('noguestrate', 'forum');
@@ -118,7 +118,7 @@
         delete_records('forum_ratings', 'post', $postid, 'userid', $USER->id);
 
 /// Updating rate
-    } else if ($oldrating = get_record('forum_ratings', 'userid', $USER->id, 'post', $post->id)) {
+    } else if ($oldrating = get_record('forum_ratings', 'userid', $USER->id, 'post', $post->id) && ($rate !=-1)) {
         if ($rate != $oldrating->rating) {
             $oldrating->rating = $rate;
             $oldrating->time   = time();
@@ -129,19 +129,24 @@
 
 /// Inserting rate
     } else {
-        $newrating = new object();
-        $newrating->userid = $USER->id;
-        $newrating->time   = time();
-        $newrating->post   = $post->id;
-        $newrating->rating = $rate;
+        if ($rate != -1) {
+            $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));
+            if (!insert_record('forum_ratings', $newrating)) {
+                print_error('cannotinsertrate', 'error', '', (object)array('id'=>$postid, 'rating'=>$rate));
+            }
         }
     }
+        
 
 /// Update grades
-    forum_update_grades($forum, $post->userid);
+    if ($rate !=-1) {
+        forum_update_grades($forum, $post->userid);
+    }
 
 /// Check user can see any rate
     $canviewanyrating = has_capability('mod/forum:viewanyrating', $context);
Index: lang/en_utf8/forum.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lang/en_utf8/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	5 Apr 2009 04:15: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/error.php,v
retrieving revision 1.26.2.22
diff -u -r1.26.2.22 error.php
--- lang/en_utf8/error.php	26 Mar 2009 21:32:34 -0000	1.26.2.22
+++ lang/en_utf8/error.php	5 Apr 2009 04:15:04 -0000
@@ -82,6 +82,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: theme/standard/styles_layout.css
===================================================================
RCS file: /cvsroot/moodle/moodle/theme/standard/styles_layout.css,v
retrieving revision 1.516.2.75
diff -u -r1.516.2.75 styles_layout.css
--- theme/standard/styles_layout.css	16 Feb 2009 03:08:47 -0000	1.516.2.75
+++ theme/standard/styles_layout.css	5 Apr 2009 04:15:06 -0000
@@ -3418,6 +3418,11 @@
   clear: both;
 }
 
+.forumpost .approvals {
+  padding-top: 1em;
+  text-align:right;
+}
+
 .forumpost .ratings {
   padding-top: 1em;
   text-align:right;
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,18 @@
+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. Suggestions and comments are welcome in the tracker. 
