]> git.mjollnir.org Git - moodle.git/commitdiff
MAJOR NEW FEATURE: Tracking of read/unread posts
authormoodler <moodler>
Sat, 29 Jan 2005 09:49:42 +0000 (09:49 +0000)
committermoodler <moodler>
Sat, 29 Jan 2005 09:49:42 +0000 (09:49 +0000)
Many thanks to Mike Churchward for his work on this and persevering
with sending updated versions to me.  :-)

Shane and I have polished it up, rewritten a few parts (display-related)
and here it is, finally in CVS!

I think there will still need to be some optimisation for the SQL,
since it's still pretty intensive. Perhaps some sort of caching in
the session that gets modified along with the database whenever
something gets read.

However if there are problems the whole thing can be switched off
in the forum module config so this is not crucially urgent.

13 files changed:
course/lib.php
lang/en/forum.php
mod/forum/config.html
mod/forum/db/mysql.php
mod/forum/db/mysql.sql
mod/forum/db/postgres7.php
mod/forum/db/postgres7.sql
mod/forum/discuss.php
mod/forum/index.php
mod/forum/lib.php
mod/forum/post.php
mod/forum/search.php
mod/forum/version.php

index 9b1a9a01603cb3b5885385703169b4f4867de5e8..0b56e2e3735288470e5b21524b20aba21a7504f7 100644 (file)
@@ -1036,6 +1036,16 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                          ' href="'.$CFG->wwwroot.'/mod/'.$mod->modname.'/view.php?id='.$mod->id.'">'.
                          $instancename.'</a></font>';
                 }
+                if ($CFG->forum_trackreadposts && $mod->modname == 'forum') {
+                    $groupmode = groupmode($course, $mod);
+                    $groupid = ($groupmode == SEPARATEGROUPS && !isteacheredit($course->id)) ?
+                        get_current_group($course->id) : false;
+                    $unread = forum_tp_count_forum_posts($mod->instance, $groupid) -
+                        forum_tp_count_forum_read_records($USER->id, $mod->instance, $groupid);
+                    $cssclass = ($unread > 0) ? 'unread' : 'read';
+                    echo '<span class="'.$cssclass.'"> '.get_string('unreadpostsnumber', 'forum', $unread).'.</span>';
+                }
+
                 if ($isediting) {
                     if ($groupbuttons) {
                         if (! $mod->groupmodelink = $groupbuttonslink) {
index 43381eeb388b4924d2be64ce5c16ac72ce177714..115b635ff634b3425c23597c3662ef55537ead74 100644 (file)
@@ -11,13 +11,18 @@ $string['allowsdiscussions'] = 'This forum allows each person to start one discu
 $string['anyfile'] = 'Any file';
 $string['attachment'] = 'Attachment';
 $string['bynameondate'] = 'by $a->name - $a->date';
+$string['configcleanreadtime'] = 'The hour of the day to clean old posts from the \'read\' table.';
 $string['configdisplaymode'] = 'The default display mode for discussions if one isn\'t set.';
 $string['configenablerssfeeds'] = 'This switch will enable the possibility of RSS feeds for all forums.  You will still need to turn feeds on manually in the settings for each forum.';
 $string['configlongpost'] = 'Any post over this length (not including HTML) is considered long.';
 $string['configmanydiscussions'] = 'Maximum number of discussions shown in a forum per page';
 $string['configmaxbytes'] = 'Default maximum size for all forum attachments on the site (subject to course limits and other local settings)';
+$string['configoldpostdays'] = 'Number of days old any post is considered read.';
 $string['configreplytouser'] = 'When a forum post is mailed out, should it contain the user\'s email address so that recipients can reply personally rather than via the forum? Even if set to \'Yes\' users can choose in their profile to keep their email address secret.';
 $string['configshortpost'] = 'Any post under this length (not including HTML) is considered short.';
+$string ['configtrackreadposts'] = 'Set to \'yes\' if you want to track read/unread for each user.';
+$string['configusermarksread'] = 'If \'yes\', the user must manually mark a post as read. '.
+                                 'If \'no\', when the post is viewed it is marked as read.';
 $string['couldnotadd'] = 'Could not add your post due to an unknown error';
 $string['couldnotdeleteratings'] = 'Sorry, that cannot be deleted as people have already rated it';
 $string['couldnotdeletereplies'] = 'Sorry, that cannot be deleted as people have already responded to it';
@@ -59,6 +64,8 @@ $string['introsocial'] = 'An open forum for chatting about anything you want to'
 $string['introteacher'] = 'A forum for teacher-only notes and discussion';
 $string['lastpost'] = 'Last post';
 $string['learningforums'] = 'Learning forums';
+$string['markread'] = 'Mark read';
+$string['markunread'] = 'Mark unread';
 $string['maxattachmentsize'] = 'Maximum attachment size';
 $string['maxtimehaspassed'] = 'Sorry, but the maximum time for editing this post ($a) has passed!';
 $string['message'] = 'Message';
@@ -147,6 +154,9 @@ $string['subscribestart'] = 'Send me email copies of posts to this forum';
 $string['subscribestop'] = 'I don\'t want email copies of posts to this forum';
 $string['subscription'] = 'Subscription';
 $string['subscriptions'] = 'Subscriptions';
+$string['unread'] = 'Unread';
+$string['unreadposts'] = 'Unread posts';
+$string['unreadpostsnumber'] = '$a posts unread';
 $string['unsubscribe'] = 'Unsubscribe from this forum';
 $string['unsubscribed'] = 'Unsubscribed';
 $string['unsubscribeshort'] = 'Unsubscribe';
index 58c422d92f7b263abeca4a9f430246e123aa5133..f43c17a90468d10e81c818243812b83f5592e883 100644 (file)
     <?php print_string("configmaxbytes", "forum") ?>
     </td>
 </tr>
+
+<tr valign="top">
+    <td align="right"><p>forum_trackreadposts:</td>
+    <td>
+    <?php
+       unset($options);
+       $options[0] = get_string("no");
+       $options[1] = get_string("yes");
+       choose_from_menu ($options, "forum_trackreadposts", $CFG->forum_trackreadposts, "", "", "");
+    ?>
+    </td>
+    <td>
+    <?php print_string("configtrackreadposts", "forum") ?>
+    </td>
+</tr>
+<tr valign="top">
+    <td align="right"><p>forum_oldpostdays:</td>
+    <td>
+    <input name="forum_oldpostdays" type="text" size="5" value="<?php p($CFG->forum_oldpostdays) ?>" />
+    </td>
+    <td>
+    <?php print_string("configoldpostdays", "forum") ?>
+    </td>
+</tr>
+<tr valign="top">
+    <td align="right"><p>forum_usermarksread:</td>
+    <td>
+    <?php
+       unset($options);
+       $options[0] = get_string("no");
+       $options[1] = get_string("yes");
+       choose_from_menu ($options, "forum_usermarksread", $CFG->forum_usermarksread, "", "", "");
+    ?>
+    </td>
+    <td>
+    <?php print_string("configusermarksread", "forum") ?>
+    </td>
+</tr>
+<tr valign="top">
+    <td align="right"><p>forum_cleanreadtime:</td>
+    <td>
+    <?php
+       unset($options);
+       $options[0] = '0';
+       $options[1] = '1';
+       $options[2] = '2';
+       $options[3] = '3';
+       $options[4] = '4';
+       $options[5] = '5';
+       $options[6] = '6';
+       $options[7] = '7';
+       $options[8] = '8';
+       $options[9] = '9';
+       $options[10] = '10';
+       $options[11] = '11';
+       $options[12] = '12';
+       $options[13] = '13';
+       $options[14] = '14';
+       $options[15] = '15';
+       $options[16] = '16';
+       $options[17] = '17';
+       $options[18] = '18';
+       $options[19] = '19';
+       $options[20] = '20';
+       $options[21] = '21';
+       $options[22] = '22';
+       $options[23] = '23';
+       choose_from_menu ($options, "forum_cleanreadtime", $CFG->forum_cleanreadtime, "", "", "");
+    ?>
+    </td>
+    <td>
+    <?php print_string("configcleanreadtime", "forum") ?>
+    </td>
+</tr>
+
 <tr valign="top">
         <td align="right"><p>forum_enablerssfeeds:</td>
         <td>
index f22da5211676c64fdec808b6ebf1fb7784b0587b..e538c753f16555e7748a53083275af48ab908391 100644 (file)
@@ -159,6 +159,22 @@ function forum_upgrade($oldversion) {
       modify_database('','ALTER TABLE prefix_forum_subscriptions ADD INDEX forum (forum);');
   }
 
+  if ($oldversion < 2005011500) {
+      modify_database('','CREATE TABLE prefix_forum_read (
+                          `id` int(10) unsigned NOT NULL auto_increment, 
+                          `userid` int(10) NOT NULL default \'0\',
+                          `forumid` int(10) NOT NULL default \'0\',
+                          `discussionid` int(10) NOT NULL default \'0\',
+                          `postid` int(10) NOT NULL default \'0\',
+                          `firstread` int(10) NOT NULL default \'0\',
+                          `lastread` int(10) NOT NULL default \'0\',
+                          PRIMARY KEY  (`id`),
+                          KEY `prefix_forum_user_forum_idx` (`userid`,`forumid`),
+                          KEY `prefix_forum_user_discussion_idx` (`userid`,`discussionid`),
+                          KEY `prefix_forum_user_post_idx` (`userid`,`postid`)
+                        ) COMMENT=\'Tracks each users read posts\';');
+  }
+
   return true;
   
 }
index e0811f695b55c3402e5106b1b8be3e9d7ca5f662..e6795becbd458e2e1540c0ed506b80a7cce6f6bf 100644 (file)
@@ -116,6 +116,24 @@ CREATE TABLE prefix_forum_subscriptions (
 ) COMMENT='Keeps track of who is subscribed to what forum';
 # --------------------------------------------------------
 
+#
+# Table structure for table `forum_read`
+#
+
+CREATE TABLE prefix_forum_read (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `userid` int(10) NOT NULL default '0',
+  `forumid` int(10) NOT NULL default '0',
+  `discussionid` int(10) NOT NULL default '0',
+  `postid` int(10) NOT NULL default '0',
+  `firstread` int(10) NOT NULL default '0',
+  `lastread` int(10) NOT NULL default '0',
+  PRIMARY KEY  (`id`),
+  KEY `prefix_forum_user_forum_idx` (`userid`,`forumid`),
+  KEY `prefix_forum_user_discussion_idx` (`userid`,`discussionid`),
+  KEY `prefix_forum_user_post_idx` (`userid`,`postid`)
+) COMMENT='Tracks each users read posts';
+
 #
 # Dumping data for table `log_display`
 #
index 94674dfa1e01222a56a67b60c686e5b24e2445d7..ef5d6f23c0f91ec2f8863154f4506fef8595ad50 100644 (file)
@@ -101,6 +101,22 @@ function forum_upgrade($oldversion) {
       modify_database('','CREATE INDEX prefix_forum_subscriptions_forum_idx ON prefix_forum_subscriptions (forum);');
   }
 
+  if ($oldversion < 2005011500) {
+      modify_database('','CREATE TABLE prefix_forum_read (
+                          id SERIAL PRIMARY KEY,
+                          userid integer default 0 NOT NULL,
+                          forumid integer default 0 NOT NULL,
+                          discussionid integer default 0 NOT NULL,
+                          postid integer default 0 NOT NULL,
+                          firstread integer default 0 NOT NULL,
+                          lastread integer default 0 NOT NULL
+                        );');
+
+      modify_database('','CREATE INDEX prefix_forum_user_forum_idx ON prefix_forum_read (userid, forumid);');
+      modify_database('','CREATE INDEX prefix_forum_user_discussion_idx ON prefix_forum_read (userid, discussionid);');
+      modify_database('','CREATE INDEX prefix_forum_user_post_idx ON prefix_forum_read (userid, postid);');
+  }
+
   return true;
 
 }
index 50c067c7b8b737eae3948d3f28eb6f0ab29c2b0f..902f15ef422404f8cdbb18cc8cdb0942315de96c 100644 (file)
@@ -119,6 +119,28 @@ CREATE TABLE prefix_forum_subscriptions (
 CREATE INDEX prefix_forum_subscriptions_userid_idx ON prefix_forum_subscriptions (userid);
 CREATE INDEX prefix_forum_subscriptions_forum_idx ON prefix_forum_subscriptions (forum);
 
+# --------------------------------------------------------
+
+
+#
+# Table structure for table `forum_read`
+#
+
+CREATE TABLE prefix_forum_read (
+  id SERIAL PRIMARY KEY,
+  userid integer NOT NULL default '0',
+  forumid integer NOT NULL default '0',
+  discussionid integer NOT NULL default '0',
+  postid integer NOT NULL default '0',
+  firstread integer NOT NULL default '0',
+  lastread integer NOT NULL default '0'
+);
+
+CREATE INDEX prefix_forum_user_forum_idx ON prefix_forum_read (userid, forumid);
+CREATE INDEX prefix_forum_user_discussion_idx ON prefix_forum_read (userid, discussionid);
+CREATE INDEX prefix_forum_user_post_idx ON prefix_forum_read (userid, postid);
+
+
 # --------------------------------------------------------
 
 #
index 566f401aa866d60e53c6a0587e039af042cd531c..825059bd16af4d1032971fa1cacd1d1de874ad3e 100644 (file)
@@ -10,6 +10,8 @@
     optional_variable($parent); // If set, then display this post and all children.
     optional_variable($mode);   // If set, changes the layout of the thread
     optional_variable($move);   // If set, moves this discussion to another forum
+    optional_variable($mark);   // Used for tracking read posts if user initiated.
+    optional_variable($postid); // Used for tracking read posts if user initiated.
 
     if (! $discussion = get_record("forum_discussions", "id", $d)) {
         error("Discussion ID was incorrect or no longer exists");
         error("Discussion no longer exists", "$CFG->wwwroot/mod/forum/view.php?f=$forum->id");
     }
 
+    if ($CFG->forum_trackreadposts && $CFG->forum_usermarksread) {
+        if ($mark == 'read') {
+            forum_tp_add_read_record($USER->id, $postid, $discussion->id, $forum->id);
+        } else if ($mark == 'unread') {
+            forum_tp_delete_read_records($USER->id, $postid);
+        }
+    }
+
     if (empty($navtail)) {
         $navtail = "<a href=\"discuss.php?d=$discussion->id\">$discussion->name</a> -> $post->subject";
     }
         print_header("$course->shortname: $discussion->name", "$course->fullname",
                  "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> ->
                   $navmiddle -> $navtail", "", "", true, $searchform, navmenu($course, $cm));
-
-        echo '<div id="forum-discuss" class="forum">';  // forum-discuss wrapper start
     } else {
         print_header("$course->shortname: $discussion->name", "$course->fullname",
                  "$navmiddle -> $navtail", "", "", true, $searchform, navmenu($course, $cm));
-
-        echo '<div id="forum-discuss" class="forum">';  // forum-discuss wrapper start
     }
 
+    echo '<div id="forum-discuss" class="forum">';  // forum-discuss wrapper start
+
 
 /// Check to see if groups are being used in this forum
 /// If so, make sure the current person is allowed to see this discussion
index 2fbd904cf0bf4accc9f92abee0b79e8d3786fecd..c8dcc6b75f3a3adfeab3f6a65a3ffdc1ada8e056 100644 (file)
@@ -35,6 +35,7 @@
     $strdescription = get_string("description");
     $strdiscussions = get_string("discussions", "forum");
     $strsubscribed = get_string("subscribed", "forum");
+    $strunreadposts = get_string("unreadposts", "forum");
     $strrss = get_string("rss");
 
     $searchform = forum_print_search_form($course, "", true, "plain");
     // Start of the table for General Forums
 
     $generaltable->head  = array ($strforum, $strdescription, $strdiscussions);
-    $generaltable->align = array ("left", "left", "center");
+    $generaltable->align = array ("left", "left", "right");
+
+    if ($CFG->forum_trackreadposts) {
+        $generaltable->head[] = $strunreadposts;
+        $generaltable->align[] = "right";
+    }
 
     if ($can_subscribe = (isstudent($course->id) or isteacher($course->id) or isadmin())) {
         $generaltable->head[] = $strsubscribed;
         $generaltable->align[] = "center";
     }
 
-    if ($show_rss = (($can_subscribe || $course->id == SITEID) &&
+    if ($show_rss = (($can_subscribe || $course->id == SITEID) && 
                      isset($CFG->enablerssfeeds) && isset($CFG->forum_enablerssfeeds) &&
                      $CFG->enablerssfeeds && $CFG->forum_enablerssfeeds)) {
         $generaltable->head[] = $strrss;
                 $count = count_records("forum_discussions", "forum", "$forum->id");
             }
 
+            if ($CFG->forum_trackreadposts) {
+                $groupid = ($groupmode==SEPARATEGROUPS && !isteacheredit($course->id)) ? $currentgroup : false;
+                $unread = forum_tp_count_forum_posts($forum->id, $groupid) -
+                          forum_tp_count_forum_read_records($USER->id, $forum->id, $groupid);
+                if ($unread > 0) {
+                    $unreadlink = '<span class="unread">'.$unread.'</span>';
+                } else {
+                    $unreadlink = '<span class="read">'.$unread.'</span>';
+                }
+            }
+
             $forum->intro = forum_shorten_post($forum->intro);
             replace_smilies($forum->intro);
             $forum->intro = "<span style=\"font-size:x-small;\">$forum->intro</span>";;
                         $sublink = "<a title=\"$subtitle\" href=\"subscribe.php?id=$forum->id\">$subscribed</a>";
                     }
                 }
-                //Depending of rsslink
+                $row = array ($forumlink, $forum->intro, "$count");
+                if ($CFG->forum_trackreadposts) {
+                    $row[] = $unreadlink;
+                }
+                $row[] = $sublink;
                 if (!empty($rsslink)) {
-                    //Save data
-                    $generaltable->data[] = array ($forumlink, "$forum->intro", "$count", $sublink, $rsslink);
-                } else {
-                    $generaltable->data[] = array ($forumlink, "$forum->intro", "$count", $sublink);
+                    $row[] = $rsslink;
                 }
+                $generaltable->data[] = $row;
             } else {
-                //Depending of rsslink
+                $row = array ($forumlink, $forum->intro, "$count");
+                if ($CFG->forum_trackreadposts) {
+                    $row[] = $unreadlink;
+                }
                 if (!empty($rsslink)) {
-                    $generaltable->data[] = array ($forumlink, "$forum->intro", "$count", $rsslink);
-                } else {
-                    $generaltable->data[] = array ($forumlink, "$forum->intro", "$count");
+                    $row[] = $rsslink;
                 }
+                $generaltable->data[] = $row;
             }
         }
     }
     $learningtable->head  = array ($strforum, $strdescription, $strdiscussions);
     $learningtable->align = array ("left", "left", "center");
 
+    if ($CFG->forum_trackreadposts) {
+        $learningtable->head[] = $strunreadposts;
+        $learningtable->align[] = 'right';
+    }
+
     if ($can_subscribe = (isstudent($course->id) or isteacher($course->id) or isadmin())) {
         $learningtable->head[] = $strsubscribed;
         $learningtable->align[] = "center";
     }
 
-    if ($show_rss = (($can_subscribe || $course->id == SITEID) &&
+    if ($show_rss = (($can_subscribe || $course->id == SITEID) && 
                      isset($CFG->enablerssfeeds) && isset($CFG->forum_enablerssfeeds) &&
                      $CFG->enablerssfeeds && $CFG->forum_enablerssfeeds)) {
         $learningtable->head[] = $strrss;
                     $count = count_records("forum_discussions", "forum", "$forum->id");
                 }
 
+                if ($CFG->forum_trackreadposts) {
+                    $groupid = ($groupmode==SEPARATEGROUPS && !isteacheredit($course->id)) ? $currentgroup : false;
+                    $unread = forum_tp_count_forum_posts($forum->id, $groupid) -
+                              forum_tp_count_forum_read_records($USER->id, $forum->id, $groupid);
+                    if ($unread > 0) {
+                        $unreadlink = '<span class="unread">'.$unread.'</span>';
+                    } else {
+                        $unreadlink = '<span class="read">'.$unread.'</span>';
+                    }
+                }
+
                 $forum->intro = forum_shorten_post($forum->intro);
                 replace_smilies($forum->intro);
                 $forum->intro = "<span style=\"font-size:x-small;\">$forum->intro</span>";
                         $rsslink = rss_get_link($course->id, $userid, "forum", $forum->id, $tooltiptext);
                     }
                 }
-
+    
                 if ($can_subscribe) {
                     if (forum_is_forcesubscribed($forum->id)) {
                         $sublink = get_string("yes");
                             $sublink = "<a title=\"$subtitle\" href=\"subscribe.php?id=$forum->id\">$subscribed</a>";
                         }
                     }
-                    //Depending of rsslink
+
+                    $row = array ($printsection, $forumlink, $forum->intro, $count);
+                    if ($CFG->forum_trackreadposts) {
+                        $row[] = $unreadlink;
+                    }
+                    $row[] = $sublink;
                     if (!empty($rsslink)) {
-                        //Save data
-                        $learningtable->data[] = array ($printsection,$forumlink, "$forum->intro", "$count", $sublink, $rsslink);
-                    } else {
-                        $learningtable->data[] = array ($printsection,$forumlink, "$forum->intro", "$count", $sublink);
+                        $row[] = $rsslink;
                     }
+                    $learningtable->data[] = $row;
+
                 } else {
-                    //Depending of rsslink
+                    $row = array ($printsection, $forumlink, $forum->intro, $count);
+                    if ($CFG->forum_trackreadposts) {
+                        $row[] = $unreadlink;
+                    }
                     if (!empty($rsslink)) {
-                        $learningtable->data[] = array ($printsection, $forumlink, "$forum->intro", "$count", $rsslink);
-                    } else {
-                        $learningtable->data[] = array ($printsection, $forumlink, "$forum->intro", "$count");
+                        $row[] = $rsslink;
                     }
+                    $learningtable->data[] = $row;
                 }
             }
         }
         print_header("$course->shortname: $strforums", "$course->fullname",
                     "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> -> $strforums",
                     "", "", true, $searchform, navmenu($course));
-
-        echo '<div id="forum-index" class="forum">';  // forum-index wrapper start
     } else {
         print_header("$course->shortname: $strforums", "$course->fullname", "$strforums",
                     "", "", true, $searchform, navmenu($course));
-
-        echo '<div id="forum-index" class="forum">';  // forum-index wrapper start
     }
 
     if ($generalforums) {
         print_table($learningtable);
     }
 
-    echo '</div>';  // forum-index wrapper end
-
     print_footer($course);
 
 ?>
index fa32a006b9c18cba776385a353883419545a8b1d..8b6ac34a9f941d84ce8184ff23a2c9858ab2124a 100644 (file)
@@ -46,6 +46,22 @@ if (!isset($CFG->forum_maxbytes)) {
     set_config("forum_maxbytes", 512000);  // Default maximum size for all forums
 }
 
+if (!isset($CFG->forum_trackreadposts)) {
+    set_config("forum_trackreadposts", true);  // Default whether user needs to mark a post as read
+}
+
+if (!isset($CFG->forum_oldpostdays)) {
+    set_config("forum_oldpostdays", 60);  // Default number of days that a post is considered old
+}
+
+if (!isset($CFG->forum_usermarksread)) {
+    set_config("forum_usermarksread", false);  // Default whether user needs to mark a post as read
+}
+
+if (!isset($CFG->forum_cleanreadtime)) {
+    set_config("forum_cleanreadtime", 2);  // Default time (hour) to execute 'clean_read_records' cron
+}
+
 if (!isset($CFG->forum_replytouser)) {
     set_config("forum_replytouser", true);  // Default maximum size for all forums
 }
@@ -182,6 +198,8 @@ function forum_delete_instance($id) {
         $result = false;
     }
 
+    forum_tp_delete_read_records(-1, -1, -1, $forum->id);
+
     if (! delete_records("forum", "id", "$forum->id")) {
         $result = false;
     }
@@ -213,6 +231,7 @@ function forum_cron () {
     $timenow   = time();
     $endtime   = $timenow - $CFG->maxeditingtime;
     $starttime = $endtime - 48 * 3600;   /// Two days earlier
+    $starttime = $endtime - 365 * 24 * 3600;   /// Two days earlier
 
     if ($posts = forum_get_unmailed_posts($starttime, $endtime)) {
 
@@ -330,6 +349,14 @@ function forum_cron () {
                                    substr($post->subject,0,30), $cm->id, $userto->id);
                     } else {
                         $mailcount++;
+
+                    /// Mark post as read if forum_usermarksread is set off
+                        if ($CFG->forum_trackreadposts && !$CFG->forum_usermarksread) {
+                            if (!forum_tp_mark_post_read($userto->id, $post, $forum->id)) {
+                                mtrace("Error: mod/forum/cron.php: Could not mark post $post->id read for user $userto->id".
+                                     " while sending email.");
+                            }
+                        }
                     }
                 }
 
@@ -463,6 +490,10 @@ function forum_cron () {
                     $postsarray = $discussionposts[$discussionid];
                     sort($postsarray);
 
+                /// Create an empty array to use for marking read posts.
+                /// (I'm sure there's already a structure I can use here, but I can't be sure.)
+                    $markread = array();
+
                     foreach ($postsarray as $postid) {
                         if (! $post = get_record("forum_posts", "id", "$postid")) {
                             mtrace("Error: Could not find post $postid");
@@ -490,6 +521,12 @@ function forum_cron () {
                             // The full treatment
                             $posttext .= forum_make_mail_text($course, $forum, $discussion, $post, $userfrom, $userto, true);
                             $posthtml .= forum_make_mail_post($post, $userfrom, $userto, $course, false, $canreply, false, false);
+
+                        /// Create an array of postid's for this user to mark as read.
+                            if ($CFG->forum_trackreadposts && !$CFG->forum_usermarksread) {
+                                $markread[$post->id]->post = $post;
+                                $markread[$post->id]->forumid = $forum->id;
+                            }
                         }
                     }
                     if ($canunsubscribe) {
@@ -511,6 +548,16 @@ function forum_cron () {
                 } else {
                     mtrace("success.");
                     $usermailcount++;
+                    
+                    /// Mark post as read if forum_usermarksread is set off
+                        if ($CFG->forum_trackreadposts && !$CFG->forum_usermarksread) {
+                            foreach ($markread as $postinfo) {
+                                if (!forum_tp_mark_post_read($userto->id, $postinfo->post, $postinfo->forumid)) {
+                                    mtrace("Error: mod/forum/cron.php: Could not mark post $postid read for user $userto->id".
+                                         " while sending digest email.");
+                                }
+                            }
+                        }
                 }
 
             }
@@ -526,6 +573,21 @@ function forum_cron () {
         $USER = $realuser;
     }
 
+    if (($lastreadclean = get_record("config", "name", "forum_lastreadclean"))) {
+        $cleantime = mktime($CFG->forum_cleanreadtime, 0);
+        $timenow = time();
+        if (($timenow > $cleantime) && ($lastreadclean->value+(24*3600) < $timenow)) {
+            $lastreadclean->value = $timenow;
+            update_record("config", $lastreadclean);
+            forum_tp_clean_read_records();
+        }
+    } else {
+        $lastreadclean->name = 'forum_lastreadclean';
+        $lastreadclean->value = time();
+        insert_record("config", $lastreadclean);
+    }
+
+
     return true;
 }
 
@@ -634,6 +696,10 @@ function forum_user_complete($course, $user, $mod, $forum) {
 
     if ($posts = forum_get_user_posts($forum->id, $user->id)) {
         foreach ($posts as $post) {
+        
+    /// Add the forum id to the post object - used by read tracking.
+            $post->forum = $forum->id;
+
             forum_print_post($post, $course->id, $ownpost=false, $reply=false, $link=false, $rate=false);
         }
 
@@ -1099,12 +1165,15 @@ function forum_count_discussion_replies($forum="0") {
 
     if ($forum) {
         $forumselect = " AND d.forum = '$forum'";
+    } else {
+        $forumselect = '';
     }
     return get_records_sql("SELECT p.discussion, (count(*)) as replies, max(p.id) as lastpostid
                               FROM {$CFG->prefix}forum_posts p,
                                    {$CFG->prefix}forum_discussions d
                              WHERE p.parent > 0
                                AND p.discussion = d.id
+                               {$forumselect}
                           GROUP BY p.discussion");
 }
 
@@ -1175,7 +1244,7 @@ function forum_get_discussions($forum="0", $forumsort="d.timemodified DESC",
                                AND p.discussion = d.id
                                AND p.parent = 0
                                AND p.userid = u.id $groupselect $userselect
-                               AND d.usermodified = um.id 
+                               AND (d.usermodified = um.id OR d.usermodified = 0) 
                           ORDER BY $forumsort");
 }
 
@@ -1413,12 +1482,14 @@ function forum_make_mail_post(&$post, $user, $touser, $course,
 
 
 function forum_print_post(&$post, $courseid, $ownpost=false, $reply=false, $link=false,
-                          $ratings=NULL, $footer="", $highlight="") {
+                          $ratings=NULL, $footer="", $highlight="", $post_read=-99) {
 
     global $USER, $CFG;
 
     static $stredit, $strdelete, $strreply, $strparent, $strprune, $strpruneheading, $threadedmode, $isteacher, $adminedit;
 
+    static $strmarkread, $strmarkunread;
+
     if (empty($stredit)) {
         $stredit = get_string('edit', 'forum');
         $strdelete = get_string('delete', 'forum');
@@ -1429,13 +1500,29 @@ function forum_print_post(&$post, $courseid, $ownpost=false, $reply=false, $link
         $threadedmode = (!empty($USER->mode) and ($USER->mode == FORUM_MODE_THREADED));
         $isteacher = isteacher($courseid);
         $adminedit = (isadmin() and !empty($CFG->admineditalways));
+        $strmarkread = get_string('markread', 'forum');
+        $strmarkunread = get_string('markunread', 'forum');
+    }
+
+    if ($CFG->forum_trackreadposts) {
+        if ($post_read == -99) {    // If we don't know yet...
+            $post_read = forum_tp_is_post_read($USER->id, $post);
+        }
+        if ($post_read) {
+            $read_style = ' read';
+        } else {
+            $read_style = ' unread';
+            echo '<a name="unread"></a>';
+        }
+    } else {
+        $read_style = '';
     }
 
-    echo "<a name=\"$post->id\"></a>";
+    echo '<a name="'.$post->id.'"></a>';
     if ($post->parent) {
-        echo '<table border="0" cellpadding="3" cellspacing="0" class="forumpost">';
+        echo '<table border="0" cellpadding="3" cellspacing="0" class="forumpost'.$read_style.'">';
     } else {
-        echo '<table border="0" cellpadding="3" cellspacing="0" class="forumpost" width="100%">';
+        echo '<table border="0" cellpadding="3" cellspacing="0" class="forumpost'.$read_style.'" width="100%">';
     }
 
     echo "<tr><td class=\"forumpostpicture\" width=\"35\" valign=\"top\">";
@@ -1451,16 +1538,20 @@ function forum_print_post(&$post, $courseid, $ownpost=false, $reply=false, $link
     if (!empty($CFG->filterall)) {      /// Put the subject through the filters
         $post->subject = filter_text("<nolink>$post->subject</nolink>", $courseid);
     }
-    echo "<p>";
     echo "<font size=\"3\"><b>$post->subject</b></font><br />";
     echo "<font size=\"2\">";
-
+    
     $fullname = fullname($post, $isteacher);
     $by->name = "<a href=\"$CFG->wwwroot/user/view.php?id=$post->userid&amp;course=$courseid\">$fullname</a>";
     $by->date = userdate($post->modified);
     print_string("bynameondate", "forum", $by);
 
-    echo "</font></p></td></tr>";
+    if ($CFG->forum_trackreadposts) {
+        echo "</font></span></td></tr>";
+    } else {
+        echo "</font></td></tr>";
+    }
+
     echo "<tr><td valign=\"top\" class=\"forumpostside\" width=\"10\">";
     if ($group = user_group($courseid, $post->userid)) {
         print_group_picture($group, $courseid, false, false, true);
@@ -1498,6 +1589,23 @@ function forum_print_post(&$post, $courseid, $ownpost=false, $reply=false, $link
 
     $commands = array();
 
+    if ($CFG->forum_trackreadposts) {
+        if ($CFG->forum_usermarksread) {
+            if ($post_read) {
+                $mcmd = '&amp;mark=unread&amp;postid='.$post->id;
+                $mtxt = $strmarkunread;
+            } else {
+                $mcmd = '&amp;mark=read&amp;postid='.$post->id;
+                $mtxt = $strmarkread;
+            }
+            if ($threadedmode) {
+                $commands[] = "<a href=\"$CFG->wwwroot/mod/forum/discuss.php?d=$post->discussion&amp;parent=$post->id$mcmd\">$mtxt</a>";
+            } else {
+                $commands[] = "<a href=\"$CFG->wwwroot/mod/forum/discuss.php?d=$post->discussion$mcmd#$post->id\">$mtxt</a>";
+            }
+        }
+    }
+
     if ($post->parent) {
         if ($threadedmode) {
             $commands[] = "<a href=\"$CFG->wwwroot/mod/forum/discuss.php?d=$post->discussion&amp;parent=$post->parent\">$strparent</a>";
@@ -1574,6 +1682,12 @@ function forum_print_post(&$post, $courseid, $ownpost=false, $reply=false, $link
     echo "</div>";
     echo "</td></tr>\n</table>\n\n";
 
+/// *** Need to get the forum ID from somewhere. Its not automatically part of post.
+/// *** Backtrack through code to find where 'post' gets set.
+    if ($CFG->forum_trackreadposts && !$CFG->forum_usermarksread && !empty($post->forum)) {
+        forum_tp_mark_post_read($USER->id, $post, $post->forum);
+    }
+
     return $ratingsmenuused;
 }
 
@@ -1611,8 +1725,20 @@ function forum_print_discussion_header(&$post, $forum, $datestring="") {
 
     if ($forum->open or $forum->type == "teacher") {   // Show the column with replies
         echo "<td class=\"forumpostheaderreplies\" align=\"center\" nowrap=\"nowrap\">";
-        echo "<a href=\"$CFG->wwwroot/mod/forum/discuss.php?d=$post->discussion\">$post->replies</a>";
+        echo "<a href=\"$CFG->wwwroot/mod/forum/discuss.php?d=$post->discussion\">";
+        echo $post->replies."</a>";
         echo "</td>\n";
+    
+        if ($CFG->forum_trackreadposts) {
+            echo '<td class="forumpostheaderreplies" align="center" nowrap="nowrap">';
+            echo "<a href=\"$CFG->wwwroot/mod/forum/discuss.php?d=$post->discussion#unread\">";
+            if ($post->unread > 0) echo '<span class="unread">';
+            echo $post->unread;
+            if ($post->unread > 0) echo '</span>';
+            echo '</a>';
+            echo "</td>\n";
+        }
+
     }
 
     echo "<td class=\"forumpostheaderdate\" align=\"right\" nowrap=\"nowrap\">";
@@ -2014,7 +2140,7 @@ function forum_add_attachment($post, $inputname,&$message) {
 
 function forum_add_new_post($post,&$message) {
 
-    global $USER;
+    global $USER, $CFG;
     
     $post->created = $post->modified = time();
     $post->mailed = "0";
@@ -2033,12 +2159,16 @@ function forum_add_new_post($post,&$message) {
     set_field("forum_discussions", "timemodified", $post->modified, "id", $post->discussion);
     set_field("forum_discussions", "usermodified", $post->userid, "id", $post->discussion);
 
+    if ($CFG->forum_trackreadposts) {
+        forum_tp_mark_post_read($post->userid, $post, $post->forum);
+    }
+
     return $post->id;
 }
 
 function forum_update_post($post,&$message) {
 
-    global $USER;
+    global $USER, $CFG;
 
     $post->modified = time();
     $post->userid = $USER->id;
@@ -2057,6 +2187,10 @@ function forum_update_post($post,&$message) {
     set_field("forum_discussions", "timemodified", $post->modified, "id", $post->discussion);
     set_field("forum_discussions", "usermodified", $post->userid, "id", $post->discussion);
 
+    if ($CFG->forum_trackreadposts) {
+        forum_tp_mark_post_read($post->userid, $post, $post->forum);
+    }
+
     return update_record("forum_posts", $post);
 }
 
@@ -2064,7 +2198,7 @@ function forum_add_discussion($discussion,&$message) {
 // Given an object containing all the necessary data,
 // create a new discussion and return the id
 
-    GLOBAL $USER;
+    GLOBAL $USER, $CFG;
 
     $timenow = time();
 
@@ -2112,6 +2246,10 @@ function forum_add_discussion($discussion,&$message) {
         return 0;
     }
 
+    if ($CFG->forum_trackreadposts) {
+        forum_tp_mark_post_read($post->userid, $post, $post->forum);
+    }
+
     return $discussion->id;
 }
 
@@ -2134,6 +2272,8 @@ function forum_delete_discussion($discussion) {
         }
     }
 
+    forum_tp_delete_read_records(-1, -1, $discussion->id);
+
     if (! delete_records("forum_discussions", "id", "$discussion->id")) {
         $result = false;
     }
@@ -2145,6 +2285,9 @@ function forum_delete_discussion($discussion) {
 function forum_delete_post($post) {
    if (delete_records("forum_posts", "id", $post->id)) {
        delete_records("forum_ratings", "post", $post->id);  // Just in case
+
+        forum_tp_delete_read_records(-1, $post->id);
+
        if ($post->attachment) {
            $discussion = get_record("forum_discussions", "id", $post->discussion);
            $post->course = $discussion->course;
@@ -2463,6 +2606,9 @@ function forum_print_latest_discussions($forum_id=0, $forum_numdiscussions=5,
         if ($forum->open or $forum->type == "teacher") {
             echo "<th>".get_string("replies", "forum")."</th>";
         }
+        if ($CFG->forum_trackreadposts) {
+            echo '<th>'.get_string('unread', 'forum').'</th>';
+        }
         echo "<th>".get_string("lastpost", "forum")."</th>";
         echo "</tr>";
     }
@@ -2482,12 +2628,19 @@ function forum_print_latest_discussions($forum_id=0, $forum_numdiscussions=5,
             $olddiscussionlink = true;
             break;
         }
+        
         if (!empty($replies[$discussion->discussion])) {
             $discussion->replies = $replies[$discussion->discussion]->replies;
             $discussion->lastpostid = $replies[$discussion->discussion]->lastpostid;
         } else {
             $discussion->replies = 0;
         }
+        if ($CFG->forum_trackreadposts) {
+        /// Add in the unread posts. Add one to the replies to include the original post.
+            $discussion->unread = $discussion->replies+1 -
+                                  forum_tp_count_discussion_read_records($USER->id, $discussion->discussion);
+        }
+
         if (!empty($USER->id)) {
             $ownpost = ($discussion->userid == $USER->id);
         } else {
@@ -2520,6 +2673,10 @@ function forum_print_latest_discussions($forum_id=0, $forum_numdiscussions=5,
                 } else {
                     $link = false;
                 }
+
+            /// Need to add in the forum id for forum_print_post.
+                $discussion->forum = $forum_id;
+
                 forum_print_post($discussion, $forum->course, $ownpost, $reply=0, $link, $assessed=false);
                 echo "<br />\n";
             break;
@@ -2553,7 +2710,7 @@ function forum_print_latest_discussions($forum_id=0, $forum_numdiscussions=5,
 
 function forum_print_discussion($course, $forum, $discussion, $post, $mode, $canreply=NULL) {
 
-    global $USER;
+    global $USER, $CFG;
 
     if (!empty($USER->id)) {
         $ownpost = ($USER->id == $post->userid);
@@ -2580,7 +2737,17 @@ function forum_print_discussion($course, $forum, $discussion, $post, $mode, $can
         }
     }
 
-    if (forum_print_post($post, $course->id, $ownpost, $reply, $link=false, $ratings)) {
+/// Add the forum id to the post object - used by read tracking.
+    $post->forum = $forum->id;
+
+    if ($CFG->forum_trackreadposts) {
+        $user_read_array = forum_tp_get_discussion_read_records($USER->id, $post->discussion);
+    } else {
+        $user_read_array = array();
+    }
+
+    if (forum_print_post($post, $course->id, $ownpost, $reply, $link=false, $ratings,
+                         '', '', (isset($user_read_array[$post->id]) || forum_tp_is_post_old($post)))) {
         $ratingsmenuused = true;
     }
 
@@ -2588,19 +2755,22 @@ function forum_print_discussion($course, $forum, $discussion, $post, $mode, $can
         case FORUM_MODE_FLATOLDEST :
         case FORUM_MODE_FLATNEWEST :
         default:
-            if (forum_print_posts_flat($post->discussion, $course->id, $mode, $ratings, $reply)) {
+            if (forum_print_posts_flat($post->discussion, $course->id, $mode, $ratings, $reply,
+                                       $user_read_array, $post->forum)) {
                 $ratingsmenuused = true;
             }
             break;
 
         case FORUM_MODE_THREADED :
-            if (forum_print_posts_threaded($post->id, $course->id, 0, $ratings, $reply)) {
+            if (forum_print_posts_threaded($post->id, $course->id, 0, $ratings, $reply,
+                                           $user_read_array, $post->forum)) {
                 $ratingsmenuused = true;
             }
             break;
 
         case FORUM_MODE_NESTED :
-            if (forum_print_posts_nested($post->id, $course->id, $ratings, $reply)) {
+            if (forum_print_posts_nested($post->id, $course->id, $ratings, $reply,
+                                         $user_read_array, $post->forum)) {
                 $ratingsmenuused = true;
             }
             break;
@@ -2618,8 +2788,10 @@ function forum_print_discussion($course, $forum, $discussion, $post, $mode, $can
     }
 }
 
-function forum_print_posts_flat($discussion, $course, $direction, $ratings, $reply) {
-    global $USER;
+/// Add the forum id to the argument list, for use in 'forum_print_post'.
+/// Add the user_read_array to the argument list.
+function forum_print_posts_flat($discussion, $course, $direction, $ratings, $reply, &$user_read_array, $forumid=0) {
+    global $USER, $CFG;
 
     $link  = false;
     $ratingsmenuused = false;
@@ -2632,8 +2804,17 @@ function forum_print_posts_flat($discussion, $course, $direction, $ratings, $rep
 
     if ($posts = forum_get_discussion_posts($discussion, $sort)) {
         foreach ($posts as $post) {
+
+        /// Add the forum id to the post object - used by read tracking.
+            if (!$CFG->forum_usermarksread) {
+                $post->forum = $forumid;
+            } else {
+                $post->forum = 0;
+            }
+
             $ownpost = ($USER->id == $post->userid);
-            if (forum_print_post($post, $course, $ownpost, $reply, $link, $ratings)) {
+            if (forum_print_post($post, $course, $ownpost, $reply, $link, $ratings,
+                                 '', '', (isset($user_read_array[$post->id]) || forum_tp_is_post_old($post)))) {
                 $ratingsmenuused = true;
             }
         }
@@ -2642,8 +2823,10 @@ function forum_print_posts_flat($discussion, $course, $direction, $ratings, $rep
     return $ratingsmenuused;
 }
 
-function forum_print_posts_threaded($parent, $course, $depth, $ratings, $reply) {
-    global $USER;
+/// Add the forum id to the argument list, for use in 'forum_print_post'.
+/// Add the user_read_array to the argument list.
+function forum_print_posts_threaded($parent, $course, $depth, $ratings, $reply, &$user_read_array, $forumid=0) {
+    global $USER, $CFG;
 
     $link  = false;
     $ratingsmenuused = false;
@@ -2654,19 +2837,39 @@ function forum_print_posts_threaded($parent, $course, $depth, $ratings, $reply)
             echo '<div class="forumpostindent">';
             if ($depth > 0) {
                 $ownpost = ($USER->id == $post->userid);
-                if (forum_print_post($post, $course, $ownpost, $reply, $link, $ratings)) {
+
+                if (!$CFG->forum_usermarksread) {
+                    $post->forum = $forumid;
+                } else {
+                    $post->forum = 0;
+                }
+
+                if (forum_print_post($post, $course, $ownpost, $reply, $link, $ratings,
+                                     '', '', (isset($user_read_array[$post->id]) || forum_tp_is_post_old($post)))) {
                     $ratingsmenuused = true;
                 }
                 echo "<br />";
             } else {
-                $by->name = fullname($post, isteacher($course->id));
+                $by->name = fullname($post, isteacher($course));
                 $by->date = userdate($post->modified);
-                echo "<p><a name=\"$post->id\"></a><font size=\"-1\"><b><a href=\"discuss.php?d=$post->discussion&amp;parent=$post->id\">$post->subject</a></b> ";
+
+                if ($CFG->forum_trackreadposts) {
+                    if (isset($user_read_array[$post->id]) || forum_tp_is_post_old($post)) {
+                        $style = '<span class="forumthread read">';
+                    } else {
+                        $style = '<span class="forumthread unread">';
+                    }
+                } else {
+                    $style = '<span class="forumthread">';
+                }
+                echo $style."<a name=\"$post->id\"></a>".
+                     "<a href=\"discuss.php?d=$post->discussion&amp;parent=$post->id\">$post->subject</a> ";
                 print_string("bynameondate", "forum", $by);
-                echo "</font></p>";
+                echo "</span>";
             }
 
-            if (forum_print_posts_threaded($post->id, $course, $depth-1, $ratings, $reply)) {
+            if (forum_print_posts_threaded($post->id, $course, $depth-1, $ratings, $reply,
+                                           $user_read_array, $forumid)) {
                 $ratingsmenuused = true;
             }
             echo "</div>\n";
@@ -2675,8 +2878,10 @@ function forum_print_posts_threaded($parent, $course, $depth, $ratings, $reply)
     return $ratingsmenuused;
 }
 
-function forum_print_posts_nested($parent, $course, $ratings, $reply) {
-    global $USER;
+/// Add the forum id to the argument list, for use in 'forum_print_post'.
+/// Add the user_read_array to the argument list.
+function forum_print_posts_nested($parent, $course, $ratings, $reply, &$user_read_array, $forumid=0) {
+    global $USER, $CFG;
 
     $link  = false;
     $ratingsmenuused = false;
@@ -2684,18 +2889,26 @@ function forum_print_posts_nested($parent, $course, $ratings, $reply) {
     if ($posts = forum_get_child_posts($parent)) {
         foreach ($posts as $post) {
 
+            echo '<div class="forumpostindent">';
             if (empty($USER->id)) {
                 $ownpost = false;
             } else {
                 $ownpost = ($USER->id == $post->userid);
             }
 
-            echo '<div class="forumpostindent">';
-            if (forum_print_post($post, $course, $ownpost, $reply, $link, $ratings)) {
+        /// Add the forum id to the post object - used by read tracking.
+            if (!$CFG->forum_usermarksread) {
+                $post->forum = $forumid;
+            } else {
+                $post->forum = 0;
+            }
+
+            if (forum_print_post($post, $course, $ownpost, $reply, $link, $ratings,
+                                 '', '', (isset($user_read_array[$post->id]) || forum_tp_is_post_old($post)))) {
                 $ratingsmenuused = true;
             }
             echo "<br />";
-            if (forum_print_posts_nested($post->id, $course, $ratings, $reply)) {
+            if (forum_print_posts_nested($post->id, $course, $ratings, $reply, $user_read_array, $forumid)) {
                 $ratingsmenuused = true;
             }
             echo "</div>\n";
@@ -2857,4 +3070,189 @@ function forum_add_user($userid, $courseid) {
     }
 }
 
+function forum_tp_add_read_record($userid, $postid, $discussionid=-1, $forumid=-1) {
+    if (($readrecord = forum_tp_get_read_records($userid, $postid)) === false) {
+        /// New read record
+        unset($readrecord);
+        $readrecord->userid = $userid;
+        $readrecord->postid = $postid;
+        $readrecord->discussionid = $discussionid;
+        $readrecord->forumid = $forumid;
+        $readrecord->firstread = time();
+        $readrecord->lastread = $readrecord->firstread;
+        return insert_record('forum_read', $readrecord, true, 'userid');
+    }
+    else {
+        /// Update read record
+        $readrecord = reset($readrecord);
+        $readrecord->lastread = time();
+
+        /// This shouldn't happen, but just in case...
+        if (!$readrecord->firstread) {
+            $readrecord->firstread = $readrecord->lastread;
+            /// Update the 'firstread' field.
+            set_field('forum_read', 'firstread', $readrecord->firstread, 'userid', $userid, 'postid', $postid);
+        }
+        if ($discussionid > -1) {
+            /// Update the 'discussionid' field.
+            set_field('forum_read', 'discussionid', $discussionid, 'userid', $userid, 'postid', $postid);
+        }
+        if ($forumid > -1) {
+            /// Update the 'forumid' field.
+            set_field('forum_read', 'forumid', $forumid, 'userid', $userid, 'postid', $postid);
+        }
+
+        $readrecord->forumid = $forumid;
+        /// Update the 'lastread' field.
+        return set_field('forum_read', 'lastread', $readrecord->lastread, 'userid', $userid, 'postid', $postid);
+    }
+}
+
+function forum_tp_get_read_records($userid=-1, $postid=-1, $discussionid=-1, $forumid=-1) {
+    /// Returns all records in the 'forum_read' table matching the passed keys, indexed
+    /// by userid.
+    $select = '';
+    if ($userid > -1) {
+        if ($select != '') $select .= ' AND ';
+        $select .= 'userid = \''.$userid.'\'';
+    }
+    if ($postid > -1) {
+        if ($select != '') $select .= ' AND ';
+        $select .= 'postid = \''.$postid.'\'';
+    }
+    if ($discussionid > -1) {
+        if ($select != '') $select .= ' AND ';
+        $select .= 'discussionid = \''.$discussionid.'\'';
+    }
+    if ($forumid > -1) {
+        if ($select != '') $select .= ' AND ';
+        $select .= 'forumid = \''.$forumid.'\'';
+    }
+
+    return get_records_select('forum_read', $select);
+}
+
+function forum_tp_get_discussion_read_records($userid, $discussionid) {
+    /// Returns all read records for the provided user and discussion, indexed by postid.
+    $select = 'userid = \''.$userid.'\' AND discussionid = \''.$discussionid.'\'';
+    $fields = 'postid, firstread, lastread';
+    return get_records_select('forum_read', $select, '', $fields);
+}
+
+function forum_tp_mark_post_read($userid, &$post, $forumid) {
+/// If its an old post, do nothing. If the record exists, the maintenance will clear it up later.
+    if (!forum_tp_is_post_old($post)) {
+        return forum_tp_add_read_record($userid, $post->id, $post->discussion, $forumid);
+    } else {
+        return true;
+    }
+}
+
+function forum_tp_is_post_read($userid, &$post) {
+    return (forum_tp_is_post_old($post) || 
+            (get_record('forum_read', 'userid', $userid, 'postid', $post->id) !== false));
+}
+
+function forum_tp_is_post_old(&$post, $time=null) {
+    global $CFG;
+
+    if (is_null($time)) $time = time();
+    return ($post->modified < ($time - ($CFG->forum_oldpostdays * 24 * 3600)));
+}
+
+function forum_tp_count_discussion_read_records($userid, $discussionid) {
+    /// Returns the count of records for the provided user and discussion.
+    global $CFG;
+
+    $cutoffdate = isset($CFG->forum_oldpostdays) ? (time() - ($CFG->forum_oldpostdays*24*60*60)) : 0;
+
+    $sql = 'SELECT COUNT(DISTINCT p.id) '.
+           'FROM '.$CFG->prefix.'forum_discussions d '.
+           'LEFT JOIN '.$CFG->prefix.'forum_read r ON d.id = r.discussionid AND r.userid = '.$userid.' '.
+           'LEFT JOIN '.$CFG->prefix.'forum_posts p ON p.discussion = d.id '.
+                'AND (p.modified < '.$cutoffdate.' OR p.id = r.postid) '.
+           'WHERE d.id = '.$discussionid;
+
+    return (count_records_sql($sql));
+}
+
+function forum_tp_count_forum_posts($forumid, $groupid=false) {
+    /// Returns the count of posts for the provided forum and [optionally] group.
+    global $CFG;
+
+    $sql = 'SELECT COUNT(*) '.
+           'FROM '.$CFG->prefix.'forum_posts fp,'.$CFG->prefix.'forum_discussions fd '.
+           'WHERE fd.forum = '.$forumid.' AND fp.discussion = fd.id';
+    if ($groupid !== false) {
+        $sql .= ' AND (fd.groupid = '.$groupid.' OR fd.groupid = -1)';
+    }
+    $count = count_records_sql($sql);
+
+
+    return $count;
+}
+
+function forum_tp_count_forum_read_records($userid, $forumid, $groupid=false) {
+    /// Returns the count of records for the provided user and forum and [optionally] group.
+    global $CFG;
+
+    $cutoffdate = isset($CFG->forum_oldpostdays) ? (time() - ($CFG->forum_oldpostdays*24*60*60)) : 0;
+
+    $groupsel = '';
+    if ($groupid !== false) {
+        $groupsel = ' AND (d.groupid = '.$groupid.' OR d.groupid = -1)';
+    }
+
+    $sql = 'SELECT COUNT(DISTINCT p.id) '.
+           'FROM '.$CFG->prefix.'forum_posts p,'.$CFG->prefix.'forum_read r,'.$CFG->prefix.'forum_discussions d '.
+           'WHERE d.forum = '.$forumid.$groupsel.' AND p.discussion = d.id AND '.
+                '((p.id = r.postid AND r.userid = '.$userid.') OR p.modified < '.$cutoffdate.' ) ';
+
+    return (count_records_sql($sql));
+}
+
+function forum_tp_delete_read_records($userid=-1, $postid=-1, $discussionid=-1, $forumid=-1) {
+/// Deletes read records for the specified index. At least one parameter must be specified.
+    $select = '';
+    if ($userid > -1) {
+        if ($select != '') $select .= ' AND ';
+        $select .= 'userid = \''.$userid.'\'';
+    }
+    if ($postid > -1) {
+        if ($select != '') $select .= ' AND ';
+        $select .= 'postid = \''.$postid.'\'';
+    }
+    if ($discussionid > -1) {
+        if ($select != '') $select .= ' AND ';
+        $select .= 'discussionid = \''.$discussionid.'\'';
+    }
+    if ($forumid > -1) {
+        if ($select != '') $select .= ' AND ';
+        $select .= 'forumid = \''.$forumid.'\'';
+    }
+    if ($select == '') {
+        return false;
+    }
+    else {
+        return delete_records_select('forum_read', $select);
+    }
+}
+
+/// Clean old records from the forum_read table.
+function forum_tp_clean_read_records() {
+    global $CFG;
+
+/// Look for records older than the cutoffdate that are still in the forum_read table.
+    $cutoffdate = isset($CFG->forum_oldpostdays) ? (time() - ($CFG->forum_oldpostdays*24*60*60)) : 0;
+    $sql = 'SELECT fr.id, fr.userid, fr.postid '.
+           'FROM '.$CFG->prefix.'forum_posts fp, '.$CFG->prefix.'forum_read fr '.
+           'WHERE fp.modified < '.$cutoffdate.' AND fp.id = fr.postid';
+echo $sql.'<br />';
+    if (($oldreadposts = get_records_sql($sql))) {
+echo 'Deleting records: ';print_object($oldreadposts);
+        foreach($oldreadposts as $oldreadpost) {
+            delete_records('forum_read', 'userid', $oldreadpost->userid, 'postid', $oldreadpost->postid);
+        }
+    }
+}
 ?>
index 90745a831e115358cfd0a98059c7402682da1643..d11f845fac29e0a85b4bc35db613bbc22d46120d 100644 (file)
 
     $cm = get_coursemodule_from_instance("forum", $forum->id, $course->id);
 
-    if (!empty($discussion) and empty($discussion->name)) {
+    if (empty($discussion->name)) {
         $discussion->name = $forum->name;
     }
 
     if (!empty($parent)) {
         forum_print_post($parent, $course->id, $ownpost=false, $reply=false, $link=false);
         if (empty($post->edit)) {
-            forum_print_posts_threaded($parent->id, $course, 0, false, false);
+            if ($CFG->forum_trackreadposts) {
+                $user_read_array = forum_tp_get_discussion_read_records($USER->id, $discussion->id);
+            } else {
+                $user_read_array = array();
+            }
+            forum_print_posts_threaded($parent->id, $course, 0, false, false, $user_read_array, $discussion->forum);
         }
         echo "<center>";
         echo "<h2>".get_string("yourreply", "forum").":</h2>";
index 9d2cb7c622661f1aadf8a67c0921524a65f19d55..4fc8be90c86c906f95ac5819d1a2b42425694ba6 100644 (file)
@@ -40,9 +40,7 @@
     if (!$search) {
         print_header_simple("$strsearch", "",
                  "<a href=\"index.php?id=$course->id\">$strforums</a> -> $strsearch", "search.search",
-                  "", "", "&nbsp;", navmenu($course));
-
-        echo '<div id="forum-search" class="forum">';  // forum-search wrapper start
+                  "", "", "&nbsp;", navmenu($course), true);
 
         print_simple_box_start("center");
         echo "<center>";
             print_header_simple("$strsearchresults", "",
                      "<a href=\"index.php?id=$course->id\">$strforums</a> ->
                       <a href=\"search.php?id=$course->id\">$strsearch</a> -> \"$search\"", "search.search",
-                      "", "", "&nbsp;", navmenu($course));
-
-            echo '<div id="forum-search" class="forum">';  // forum-search wrapper start
-
+                      "", "", "&nbsp;", navmenu($course), true);
             print_heading(get_string("nopostscontaining", "forum", $search));
 
             print_simple_box_start("center");
@@ -78,9 +73,6 @@
             echo "</p>";
             echo "</center>";
             print_simple_box_end();
-
-            echo '</div>';  // forum-search wrapper end
-
             print_footer($course);
             exit;
         }
@@ -88,9 +80,7 @@
         print_header_simple("$strsearchresults", "",
                  "<a href=\"index.php?id=$course->id\">$strforums</a> ->
                   <a href=\"search.php?id=$course->id\">$strsearch</a> -> \"$search\"", "search.search",
-                  "", "",  $searchform, navmenu($course));
-
-        echo '<div id="forum-search" class="forum">';  // forum-search wrapper start
+                  "", "",  $searchform, navmenu($course), true);
 
         print_heading("$strsearchresults: $totalcount");
 
 
             $post->subject = $fullsubject;
 
+            /// Add the forum id to the post object - used by read tracking.
+                $post->forum = $forum->id;
+
             $fulllink = "<a href=\"discuss.php?d=$post->discussion#$post->id\">".get_string("postincontext", "forum")."</a>";
             forum_print_post($post, $course->id, false, false, false, false, $fulllink, $search);
 
         echo "</center>";
     }
 
-    echo '</div>';  // forum-search wrapper end
-
     print_footer($course);
 
 ?>
index 3a4990439d6460471f1012d4a2fd5d3da947b7c6..2c411dc13ab9488f57b610975aaf22dc3e346730 100644 (file)
@@ -5,7 +5,7 @@
 //  This fragment is called by /admin/index.php
 ////////////////////////////////////////////////////////////////////////////////
 
-$module->version  = 2004111700;
+$module->version  = 2005011500;
 $module->requires = 2004091700;  // Requires this Moodle version
 $module->cron     = 60;