From dc19b22fb8397dcd7697db09fbb808d91d9fc0c8 Mon Sep 17 00:00:00 2001
From: Dries Buytaert <dries@buytaert.net>
Date: Fri, 14 Mar 2003 20:41:27 +0000
Subject: [PATCH] - Modified patch of Moshe.  Enhances the tracker module so it
 displayes recent   *nodes* in addition to comments.  This will be helpful for
 tracking down new   book nodes, blog posts, news items, and other stuff which
 isn't interesting   enough to be promoted to the home page.

---
 modules/comment.module         | 61 +++--------------------
 modules/comment/comment.module | 61 +++--------------------
 modules/node.module            | 65 ++++++++++++++++++++++++-
 modules/node/node.module       | 65 ++++++++++++++++++++++++-
 modules/tracker.module         | 89 ++++++++++++----------------------
 modules/tracker/tracker.module | 89 ++++++++++++----------------------
 6 files changed, 206 insertions(+), 224 deletions(-)

diff --git a/modules/comment.module b/modules/comment.module
index e74c3468a242..b86560637067 100644
--- a/modules/comment.module
+++ b/modules/comment.module
@@ -8,7 +8,7 @@ function comment_help() {
   $output .= "<p>The comment module enables users to submit posts that are directly associated with a piece of content.  These associated posts are called <i>comments</i>.  Comments may be <i>threaded</i>, which means that Drupal keeps track of multiple subconversations around a piece of content.  Threading helps to keep the comment conversation more organized.  Users are presented with several ways to view the comment conversation, and if desired, users may easily choose a <i>flat</i> presentation of comments instead of threaded.  Further, users may choose to order their comments view by <i>newest first</i> or by <i>oldest first</i>.  Finally, users may view a folded list or an expanded list of comments.  Folded limits the comment display to <i>subject</i> only.  Drupal remembers the comment view preference of each registered user whenever he changes a view setting.</p>";
   $output .= "<p>Users may also choose to view a maximum number of comments; if there are more comments, navigation links are dispayed.</p>";
   $output .= "<p>Since a busy site generates lots of comments, Drupal takes care to present a personalized view of comments for each user.  The home page lists displays the number of read and unread comments for a given post for the current user.  Also, the tracker module (when installed) displays all recent comments on the site.  Finally, comments which the user has not yet read are highlighted with a red star (this graphic may depend on the current theme).</p>";
-  $output .= "<p>Comments behave like other user submissions in Drupal.  Specifically, ". l("filters", "admin/system&amp;type=filter") ." like smileys and HTML work fine if the administrator has enabled them.  Also, throttles are usually enabled to prevent a single user from spamming the web site with too many comments in a short period of time.</p>";
+  $output .= "<p>Comments behave like other user submissions in Drupal.  Specifically, ". l("filters", "admin/system/filters") ." like smileys and HTML work fine if the administrator has enabled them.  Also, throttles are usually enabled to prevent a single user from spamming the web site with too many comments in a short period of time.</p>";
   $output .= "<p>Administrators may control which persons are allowed to submit and administer comments.  These controls appear in the ". l("user permissions", "admin/user/permission") ." administration page.  Additionally, administrators may edit or search through comments on the ". l("comments admininistration page", "admin/comment") .", as well as set the default display view for new users. Administrators can also state whether a certain role will have their comments published immediately, or just put in a queue to be reviewed.</p>";
   $output .= "<p>If you really have a lot of comments, you can enable moderation. You assign moderation permissions to role(s), then setup some \"moderation votes\"; these votes will appear to moderators in a dropdown menu near the comment. You also have to assign, for every role and every vote, a value, which can be either positive or negative; use the moderation matrix to do this. This allows for some roles having greater \"weight\" in their moderation, if you wish. If you set a value to 0, that vote won't be available to that role. When a user moderates, the value of their vote is added or subtracted to the score of that comment. Finally, you may want to setup the comment thresholds: these are floor/ceiling values which users see in the comment control panel. Threshholds are useful for hiding poorly rated comments while reading your site.</p>";
 
@@ -357,7 +357,7 @@ function comment_view($comment, $links = "", $visible = 1) {
   ** Switch to folded/unfolded view of the comment
   */
 
-  if (comment_is_new($comment)) {
+  if (node_is_new($comment->nid, $comment->timestamp)) {
     $comment->new = 1;
     print "<a name=\"new\"></a>\n";
   }
@@ -594,11 +594,6 @@ function comment_render($node, $cid = 0) {
       theme("box", t("Post new comment"), comment_form(array("nid" => $nid)));
     }
 
-    /*
-    ** Tag the node's comments as being read:
-    */
-
-    comment_tag_new($nid);
   }
 }
 
@@ -658,8 +653,8 @@ function comment_link($type, $node = 0, $main = 0) {
   }
 
   if ($type == "admin" && user_access("administer comments")) {
-    $help["general"] = "To be written: description of comment module.  Anyone?";
-    $help["settings"] = "If you really have a lot of comments, you can enable moderation. You assign moderation permissions to role(s), then setup some 'moderation votes'; these votes will appear to moderators in a dropdown menu near the comment. You also have to assign, for every role and every vote, a value, which can be either positive or negative; use the moderation matrix to do this. This allows for some roles having greater 'weight' in their moderation, if you wish. If you set a value to 0, that vote won't be available to that role. When a user moderates, the value of their vote is added or subtracted to the score of that comment. Finally, you may want to setup the comment thresholds: these are floor/ceiling values which users see in the comment control panel. Threshholds are useful for hiding poorly rated comments while reading your site.";
+     $help["general"] = t("Comments let users give feedback to content authors.  Here you may review/approve/deny recent comments, and configure moderation if desired.");
++    $help["settings"] = t("If you really have a lot of comments, you can enable moderation.  You assign moderation permissions to role(s), then setup some 'moderation votes'; these votes will appear to moderators in a dropdown menu near the comment.  You also have to assign, for every role and every vote, a value, which can be either positive or negative; use the moderation matrix to do this.  This allows for some roles having greater 'weight' in their moderation, if you wish.  If you set a value to 0, that vote won't be available to that role.  When a user moderates, the value of their vote is added or subtracted to the score of that comment.  Finally, you may want to setup the comment thresholds: these are floor/ceiling values which users see in the comment control panel.  Threshholds are useful for hiding poorly rated comments while reading your site.");
 
     menu("admin/comment", "comment management", "comment_admin", $help["general"], 2);
     menu("admin/comment/0", "new or updated comments", "comment_admin");
@@ -806,7 +801,7 @@ function comment_admin_overview($status = 0) {
 
   $header = array(t("subject"), t("author"), t("status"), array("data" => t("operations"), "colspan" => 2));
   while ($comment = db_fetch_object($result)) {
-    $rows[] = array(l($comment->subject, "node/view/$comment->nid/$comment->cid#$comment->cid", array("title" => htmlentities(substr($comment->comment, 0, 128)))) ." ". (comment_is_new($comment) ? theme_mark() : ""), format_name($comment), ($comment->status == 0 ? t("published") : t("not published")) ."</td><td>". l(t("edit comment"), "admin/comment/edit/$comment->cid"), l(t("delete comment"), "admin/comment/delete/$comment->cid"));
+    $rows[] = array(l($comment->subject, "node/view/$comment->nid/$comment->cid#$comment->cid", array("title" => htmlentities(substr($comment->comment, 0, 128)))) ." ". (node_is_new($comment->nid, $comment->timestamp) ? theme_mark() : ""), format_name($comment), ($comment->status == 0 ? t("published") : t("not published")) ."</td><td>". l(t("edit comment"), "admin/comment/edit/$comment->cid"), l(t("delete comment"), "admin/comment/delete/$comment->cid"));
   }
 
   if ($pager = pager_display(NULL, 50, 0, "admin")) {
@@ -1339,7 +1334,7 @@ function comment_num_replies($id) {
 }
 
 /**
- * get number of new comments and id of first new
+ * get number of new comments for current user and specified node
  *
  * @param $nid       node-id to count comments for
  * @param $timestamp time to count from (defaults to time of last user access to node)
@@ -1354,13 +1349,11 @@ function comment_num_new($nid, $timestamp = 0) {
     */
 
     if (!$timestamp) {
-      $history = db_fetch_object(db_query("SELECT timestamp FROM history WHERE uid = '$user->uid' AND nid = '%d'", $nid));
-      $timestamp = $history->timestamp ? $history->timestamp : 0;
+      $timestamp = node_last_viewed($nid);
     }
 
     /*
-    ** Use the timestamp to retrieve the number of new comments and the
-    ** ID of first new comment.
+    ** Use the timestamp to retrieve the number of new comments
     */
 
     $result = db_result(db_query("SELECT COUNT(c.cid) FROM node n LEFT JOIN comments c ON n.nid = c.nid WHERE n.nid = '%d' AND timestamp > '%d' AND c.status = 0", $nid, $timestamp));
@@ -1373,44 +1366,6 @@ function comment_num_new($nid, $timestamp = 0) {
 
 }
 
-function comment_tag_new($nid) {
-  global $user;
-
-  if ($user->uid) {
-    $nid = check_query($nid);
-
-    $result = db_query("SELECT timestamp FROM history WHERE uid = '$user->uid' AND nid = '%d'", $nid);
-    if (db_fetch_object($result)) {
-      db_query("UPDATE history SET timestamp = '%d' WHERE uid = '$user->uid' AND nid = '%d'", time(), $nid);
-    }
-    else {
-      db_query("INSERT INTO history (uid, nid, timestamp) VALUES ('%d', '%d', '%d')", $user->uid, $nid, time());
-    }
-  }
-}
-
-function comment_is_new($comment) {
-  global $user;
-  static $cache;
-
-  if (!$cache[$comment->nid]) {
-    if ($user->uid) {
-      $history = db_fetch_object(db_query("SELECT timestamp FROM history WHERE uid = '$user->uid' AND nid = '%d'", $comment->nid));
-      $cache[$comment->nid] = $history->timestamp ? $history->timestamp : 0;
-    }
-    else {
-      $cache[$comment->nid] = time();
-    }
-  }
-
-  if ($comment->timestamp > $cache[$comment->nid]) {
-    return 1;
-  }
-  else {
-    return 0;
-  }
-}
-
 function comment_thread_structure($comments, $pid, $depth, $structure) {
   $depth++;
 
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index e74c3468a242..b86560637067 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -8,7 +8,7 @@ function comment_help() {
   $output .= "<p>The comment module enables users to submit posts that are directly associated with a piece of content.  These associated posts are called <i>comments</i>.  Comments may be <i>threaded</i>, which means that Drupal keeps track of multiple subconversations around a piece of content.  Threading helps to keep the comment conversation more organized.  Users are presented with several ways to view the comment conversation, and if desired, users may easily choose a <i>flat</i> presentation of comments instead of threaded.  Further, users may choose to order their comments view by <i>newest first</i> or by <i>oldest first</i>.  Finally, users may view a folded list or an expanded list of comments.  Folded limits the comment display to <i>subject</i> only.  Drupal remembers the comment view preference of each registered user whenever he changes a view setting.</p>";
   $output .= "<p>Users may also choose to view a maximum number of comments; if there are more comments, navigation links are dispayed.</p>";
   $output .= "<p>Since a busy site generates lots of comments, Drupal takes care to present a personalized view of comments for each user.  The home page lists displays the number of read and unread comments for a given post for the current user.  Also, the tracker module (when installed) displays all recent comments on the site.  Finally, comments which the user has not yet read are highlighted with a red star (this graphic may depend on the current theme).</p>";
-  $output .= "<p>Comments behave like other user submissions in Drupal.  Specifically, ". l("filters", "admin/system&amp;type=filter") ." like smileys and HTML work fine if the administrator has enabled them.  Also, throttles are usually enabled to prevent a single user from spamming the web site with too many comments in a short period of time.</p>";
+  $output .= "<p>Comments behave like other user submissions in Drupal.  Specifically, ". l("filters", "admin/system/filters") ." like smileys and HTML work fine if the administrator has enabled them.  Also, throttles are usually enabled to prevent a single user from spamming the web site with too many comments in a short period of time.</p>";
   $output .= "<p>Administrators may control which persons are allowed to submit and administer comments.  These controls appear in the ". l("user permissions", "admin/user/permission") ." administration page.  Additionally, administrators may edit or search through comments on the ". l("comments admininistration page", "admin/comment") .", as well as set the default display view for new users. Administrators can also state whether a certain role will have their comments published immediately, or just put in a queue to be reviewed.</p>";
   $output .= "<p>If you really have a lot of comments, you can enable moderation. You assign moderation permissions to role(s), then setup some \"moderation votes\"; these votes will appear to moderators in a dropdown menu near the comment. You also have to assign, for every role and every vote, a value, which can be either positive or negative; use the moderation matrix to do this. This allows for some roles having greater \"weight\" in their moderation, if you wish. If you set a value to 0, that vote won't be available to that role. When a user moderates, the value of their vote is added or subtracted to the score of that comment. Finally, you may want to setup the comment thresholds: these are floor/ceiling values which users see in the comment control panel. Threshholds are useful for hiding poorly rated comments while reading your site.</p>";
 
@@ -357,7 +357,7 @@ function comment_view($comment, $links = "", $visible = 1) {
   ** Switch to folded/unfolded view of the comment
   */
 
-  if (comment_is_new($comment)) {
+  if (node_is_new($comment->nid, $comment->timestamp)) {
     $comment->new = 1;
     print "<a name=\"new\"></a>\n";
   }
@@ -594,11 +594,6 @@ function comment_render($node, $cid = 0) {
       theme("box", t("Post new comment"), comment_form(array("nid" => $nid)));
     }
 
-    /*
-    ** Tag the node's comments as being read:
-    */
-
-    comment_tag_new($nid);
   }
 }
 
@@ -658,8 +653,8 @@ function comment_link($type, $node = 0, $main = 0) {
   }
 
   if ($type == "admin" && user_access("administer comments")) {
-    $help["general"] = "To be written: description of comment module.  Anyone?";
-    $help["settings"] = "If you really have a lot of comments, you can enable moderation. You assign moderation permissions to role(s), then setup some 'moderation votes'; these votes will appear to moderators in a dropdown menu near the comment. You also have to assign, for every role and every vote, a value, which can be either positive or negative; use the moderation matrix to do this. This allows for some roles having greater 'weight' in their moderation, if you wish. If you set a value to 0, that vote won't be available to that role. When a user moderates, the value of their vote is added or subtracted to the score of that comment. Finally, you may want to setup the comment thresholds: these are floor/ceiling values which users see in the comment control panel. Threshholds are useful for hiding poorly rated comments while reading your site.";
+     $help["general"] = t("Comments let users give feedback to content authors.  Here you may review/approve/deny recent comments, and configure moderation if desired.");
++    $help["settings"] = t("If you really have a lot of comments, you can enable moderation.  You assign moderation permissions to role(s), then setup some 'moderation votes'; these votes will appear to moderators in a dropdown menu near the comment.  You also have to assign, for every role and every vote, a value, which can be either positive or negative; use the moderation matrix to do this.  This allows for some roles having greater 'weight' in their moderation, if you wish.  If you set a value to 0, that vote won't be available to that role.  When a user moderates, the value of their vote is added or subtracted to the score of that comment.  Finally, you may want to setup the comment thresholds: these are floor/ceiling values which users see in the comment control panel.  Threshholds are useful for hiding poorly rated comments while reading your site.");
 
     menu("admin/comment", "comment management", "comment_admin", $help["general"], 2);
     menu("admin/comment/0", "new or updated comments", "comment_admin");
@@ -806,7 +801,7 @@ function comment_admin_overview($status = 0) {
 
   $header = array(t("subject"), t("author"), t("status"), array("data" => t("operations"), "colspan" => 2));
   while ($comment = db_fetch_object($result)) {
-    $rows[] = array(l($comment->subject, "node/view/$comment->nid/$comment->cid#$comment->cid", array("title" => htmlentities(substr($comment->comment, 0, 128)))) ." ". (comment_is_new($comment) ? theme_mark() : ""), format_name($comment), ($comment->status == 0 ? t("published") : t("not published")) ."</td><td>". l(t("edit comment"), "admin/comment/edit/$comment->cid"), l(t("delete comment"), "admin/comment/delete/$comment->cid"));
+    $rows[] = array(l($comment->subject, "node/view/$comment->nid/$comment->cid#$comment->cid", array("title" => htmlentities(substr($comment->comment, 0, 128)))) ." ". (node_is_new($comment->nid, $comment->timestamp) ? theme_mark() : ""), format_name($comment), ($comment->status == 0 ? t("published") : t("not published")) ."</td><td>". l(t("edit comment"), "admin/comment/edit/$comment->cid"), l(t("delete comment"), "admin/comment/delete/$comment->cid"));
   }
 
   if ($pager = pager_display(NULL, 50, 0, "admin")) {
@@ -1339,7 +1334,7 @@ function comment_num_replies($id) {
 }
 
 /**
- * get number of new comments and id of first new
+ * get number of new comments for current user and specified node
  *
  * @param $nid       node-id to count comments for
  * @param $timestamp time to count from (defaults to time of last user access to node)
@@ -1354,13 +1349,11 @@ function comment_num_new($nid, $timestamp = 0) {
     */
 
     if (!$timestamp) {
-      $history = db_fetch_object(db_query("SELECT timestamp FROM history WHERE uid = '$user->uid' AND nid = '%d'", $nid));
-      $timestamp = $history->timestamp ? $history->timestamp : 0;
+      $timestamp = node_last_viewed($nid);
     }
 
     /*
-    ** Use the timestamp to retrieve the number of new comments and the
-    ** ID of first new comment.
+    ** Use the timestamp to retrieve the number of new comments
     */
 
     $result = db_result(db_query("SELECT COUNT(c.cid) FROM node n LEFT JOIN comments c ON n.nid = c.nid WHERE n.nid = '%d' AND timestamp > '%d' AND c.status = 0", $nid, $timestamp));
@@ -1373,44 +1366,6 @@ function comment_num_new($nid, $timestamp = 0) {
 
 }
 
-function comment_tag_new($nid) {
-  global $user;
-
-  if ($user->uid) {
-    $nid = check_query($nid);
-
-    $result = db_query("SELECT timestamp FROM history WHERE uid = '$user->uid' AND nid = '%d'", $nid);
-    if (db_fetch_object($result)) {
-      db_query("UPDATE history SET timestamp = '%d' WHERE uid = '$user->uid' AND nid = '%d'", time(), $nid);
-    }
-    else {
-      db_query("INSERT INTO history (uid, nid, timestamp) VALUES ('%d', '%d', '%d')", $user->uid, $nid, time());
-    }
-  }
-}
-
-function comment_is_new($comment) {
-  global $user;
-  static $cache;
-
-  if (!$cache[$comment->nid]) {
-    if ($user->uid) {
-      $history = db_fetch_object(db_query("SELECT timestamp FROM history WHERE uid = '$user->uid' AND nid = '%d'", $comment->nid));
-      $cache[$comment->nid] = $history->timestamp ? $history->timestamp : 0;
-    }
-    else {
-      $cache[$comment->nid] = time();
-    }
-  }
-
-  if ($comment->timestamp > $cache[$comment->nid]) {
-    return 1;
-  }
-  else {
-    return 0;
-  }
-}
-
 function comment_thread_structure($comments, $pid, $depth, $structure) {
   $depth++;
 
diff --git a/modules/node.module b/modules/node.module
index cbb47550078d..04611cdd9a37 100644
--- a/modules/node.module
+++ b/modules/node.module
@@ -37,6 +37,62 @@ function node_title_list($result, $title = NULL) {
   return theme("theme_item_list", $items, $title);
 }
 
+// Update the 'last viewed' timestamp of the specified node for current user.
+function node_tag_new($nid) {
+  global $user;
+
+  if ($user->uid) {
+    $nid = check_query($nid);
+
+    $result = db_query("SELECT timestamp FROM history WHERE uid = '%d' AND nid = '%d'", $user->uid, $nid);
+    if (db_fetch_object($result)) {
+      db_query("UPDATE history SET timestamp = '%d' WHERE uid = '%d' AND nid = '%d'", time(), $user->uid, $nid);
+    }
+    else {
+      db_query("INSERT INTO history (uid, nid, timestamp) VALUES ('%d', '%d', '%d')", $user->uid, $nid, time());
+    }
+  }
+}
+
+/*
+** Retrieves the timestamp at which the current user last viewed the
+** specified node.
+*/
+function node_last_viewed($nid) {
+  global $user;
+
+  $history = db_fetch_object(db_query("SELECT timestamp FROM history WHERE uid = '$user->uid' AND nid = '%d'", $nid));
+  return ($history->timestamp ? $history->timestamp : 0);
+}
+
+/**
+ * Determines whether the supplied timestamp is newer than the user's last view of a given node
+ *
+ * @param $nid       node-id twhose history supplies the 'last viewed' timestamp
+ * @param $timestamp time which is compared against node's 'last veiwed' timestamp
+*/
+function node_is_new($nid, $timestamp) {
+  global $user;
+  static $cache;
+
+  if (!$cache[$nid]) {
+    if ($user->uid) {
+      $history = db_fetch_object(db_query("SELECT timestamp FROM history WHERE uid = '%d' AND nid = '%d'", $user->uid, $nid));
+      $cache[$nid] = $history->timestamp ? $history->timestamp : 0;
+    }
+    else {
+      $cache[$nid] = time();
+    }
+  }
+
+  if ($timestamp > $cache[$nid]) {
+    return 1;
+  }
+  else {
+    return 0;
+  }
+}
+
 function node_teaser($body) {
 
   $size = variable_get("teaser_length", 600);
@@ -299,6 +355,7 @@ function node_view($node, $main = 0) {
   }
 }
 
+
 function node_show($nid, $cid) {
   global $revision;
 
@@ -314,6 +371,12 @@ function node_show($nid, $cid) {
     if (function_exists("comment_render") && $node->comment) {
       comment_render($node, $cid);
     }
+
+    /*
+    ** Update the history table, stating that this user viewed this node.
+    */
+
+    node_tag_new($node->nid);
   }
 }
 
@@ -512,7 +575,7 @@ function node_admin_nodes() {
   $header = array(t("title"), t("type"), t("author"), t("status"), array("data" => t("operations"), "colspan" => 2));
 
   while ($node = db_fetch_object($result)) {
-    $rows[] = array(l($node->title, "node/view/$node->nid"), module_invoke($node->type, "node", "name"), format_name($node), ($node->status ? t("published") : t("not published")), l(t("edit node"), "admin/node/edit/$node->nid"), l(t("delete node"), "admin/node/delete/$node->nid"));
+    $rows[] = array(l($node->title, "node/view/$node->nid") ." ". (node_is_new($node->nid, $node->changed) ? theme_mark() : ""), module_invoke($node->type, "node", "name"), format_name($node), ($node->status ? t("published") : t("not published")), l(t("edit node"), "admin/node/edit/$node->nid"), l(t("delete node"), "admin/node/delete/$node->nid"));
   }
 
   if ($pager = pager_display(NULL, 50, 0, "admin")) {
diff --git a/modules/node/node.module b/modules/node/node.module
index cbb47550078d..04611cdd9a37 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -37,6 +37,62 @@ function node_title_list($result, $title = NULL) {
   return theme("theme_item_list", $items, $title);
 }
 
+// Update the 'last viewed' timestamp of the specified node for current user.
+function node_tag_new($nid) {
+  global $user;
+
+  if ($user->uid) {
+    $nid = check_query($nid);
+
+    $result = db_query("SELECT timestamp FROM history WHERE uid = '%d' AND nid = '%d'", $user->uid, $nid);
+    if (db_fetch_object($result)) {
+      db_query("UPDATE history SET timestamp = '%d' WHERE uid = '%d' AND nid = '%d'", time(), $user->uid, $nid);
+    }
+    else {
+      db_query("INSERT INTO history (uid, nid, timestamp) VALUES ('%d', '%d', '%d')", $user->uid, $nid, time());
+    }
+  }
+}
+
+/*
+** Retrieves the timestamp at which the current user last viewed the
+** specified node.
+*/
+function node_last_viewed($nid) {
+  global $user;
+
+  $history = db_fetch_object(db_query("SELECT timestamp FROM history WHERE uid = '$user->uid' AND nid = '%d'", $nid));
+  return ($history->timestamp ? $history->timestamp : 0);
+}
+
+/**
+ * Determines whether the supplied timestamp is newer than the user's last view of a given node
+ *
+ * @param $nid       node-id twhose history supplies the 'last viewed' timestamp
+ * @param $timestamp time which is compared against node's 'last veiwed' timestamp
+*/
+function node_is_new($nid, $timestamp) {
+  global $user;
+  static $cache;
+
+  if (!$cache[$nid]) {
+    if ($user->uid) {
+      $history = db_fetch_object(db_query("SELECT timestamp FROM history WHERE uid = '%d' AND nid = '%d'", $user->uid, $nid));
+      $cache[$nid] = $history->timestamp ? $history->timestamp : 0;
+    }
+    else {
+      $cache[$nid] = time();
+    }
+  }
+
+  if ($timestamp > $cache[$nid]) {
+    return 1;
+  }
+  else {
+    return 0;
+  }
+}
+
 function node_teaser($body) {
 
   $size = variable_get("teaser_length", 600);
@@ -299,6 +355,7 @@ function node_view($node, $main = 0) {
   }
 }
 
+
 function node_show($nid, $cid) {
   global $revision;
 
@@ -314,6 +371,12 @@ function node_show($nid, $cid) {
     if (function_exists("comment_render") && $node->comment) {
       comment_render($node, $cid);
     }
+
+    /*
+    ** Update the history table, stating that this user viewed this node.
+    */
+
+    node_tag_new($node->nid);
   }
 }
 
@@ -512,7 +575,7 @@ function node_admin_nodes() {
   $header = array(t("title"), t("type"), t("author"), t("status"), array("data" => t("operations"), "colspan" => 2));
 
   while ($node = db_fetch_object($result)) {
-    $rows[] = array(l($node->title, "node/view/$node->nid"), module_invoke($node->type, "node", "name"), format_name($node), ($node->status ? t("published") : t("not published")), l(t("edit node"), "admin/node/edit/$node->nid"), l(t("delete node"), "admin/node/delete/$node->nid"));
+    $rows[] = array(l($node->title, "node/view/$node->nid") ." ". (node_is_new($node->nid, $node->changed) ? theme_mark() : ""), module_invoke($node->type, "node", "name"), format_name($node), ($node->status ? t("published") : t("not published")), l(t("edit node"), "admin/node/edit/$node->nid"), l(t("delete node"), "admin/node/delete/$node->nid"));
   }
 
   if ($pager = pager_display(NULL, 50, 0, "admin")) {
diff --git a/modules/tracker.module b/modules/tracker.module
index e0ea2f9a0b42..f7563ab4de9f 100644
--- a/modules/tracker.module
+++ b/modules/tracker.module
@@ -2,103 +2,76 @@
 // $Id$
 
 function tracker_help() {
-  $output .= "<p>The tracker module is a handy module for displaying the most recent comments happenning all over your web site.  By following the <i>view new comments</i> link in the user block, a user may quickly review all recent comments.  When a user first arrives at the main tracker page, she sees all recent comments in reverse chronological order, grouped by post.  In addition, a self-centered user may choose to display only his own comments.</p>";
+  $output .= "<p>The tracker module is a handy module for displaying the most recent posts.  By following the <i>view recent posts</i> link in the user block, a user may quickly review all recent postings.</p>";
   return $output;
 }
 
 function tracker_system($field){
-  $system["description"] = t("Enables tracking of recent and new comments for users.");
+  $system["description"] = t("Enables tracking of recent posts for users.");
   return $system[$field];
 }
 
 function tracker_link($type) {
 
-  if ($type == "menu.view" && user_access("access comments")) {
-    $links[] = l(t("view new comments"), "tracker", array("title" => t("Display an overview of the recent comments.")));
+  if ($type == "menu.view" && user_access("access content")) {
+    $links[] = l(t("view recent posts"), "tracker", array("title" => t("Display an overview of the recent posts.")));
   }
 
   return $links ? $links : array();
 }
 
-function tracker_settings() {
-  $period = array(3600 => format_interval(3600), 10800 => format_interval(10800), 21600 => format_interval(21600), 32400 => format_interval(32400), 43200 => format_interval(43200), 86400 => format_interval(86400), 172800 => format_interval(172800), 259200 => format_interval(259200), 604800 => format_interval(604800), 1209600 => format_interval(1209600), 2419200 => format_interval(2419200), 1000000000 => "All");
-  $output .= form_select("Show comments more recent than", "tracker_period", variable_get("tracker_period", 259200), $period, "Comments younger than this get displayed.");
-  return $output;
-}
-
-function tracker_comments($id = 0) {
-  $period = time() - variable_get("tracker_period", 259200);  // all comments of the past 3 days if not configured to a different value
+function tracker_posts($id = 0) {
 
   if ($id) {
-    $sresult = db_query("SELECT n.nid, n.title, COUNT(n.nid) AS comments, MAX(c.timestamp) AS last_comment FROM comments c LEFT JOIN node n ON c.nid = n.nid WHERE c.status = 0 AND c.timestamp > $period AND c.uid = '%s' GROUP BY n.nid, n.title ORDER BY last_comment DESC LIMIT 10", $id);
+    $sresult = db_query_range("SELECT n.nid, n.title, n.type, n.changed, n.uid, u.name, GREATEST(n.changed, c.timestamp) AS last_activity FROM node n LEFT JOIN comments c ON n.nid = c.nid LEFT JOIN users u ON n.uid = u.uid WHERE n.uid = '". check_query($id) ."' AND n.status = 1 GROUP BY n.nid, n.title, n.type, n.changed, n.nid, u.name ORDER BY last_activity DESC", 0, 15);
   }
   else {
-    $sresult = db_query("SELECT n.nid, n.title, COUNT(n.nid) AS comments, MAX(c.timestamp) AS last_comment FROM comments c LEFT JOIN node n ON c.nid = n.nid WHERE c.status = 0 AND c.timestamp > $period GROUP BY n.nid, n.title ORDER BY last_comment DESC LIMIT 10");
+    $sresult = db_query_range("SELECT n.nid, n.title, n.type, n.changed, n.uid, u.name, GREATEST(n.changed, c.timestamp) AS last_activity FROM node n LEFT JOIN comments c ON n.nid = c.nid LEFT JOIN users u ON n.uid = u.uid WHERE n.status = 1 GROUP BY n.nid, n.title, n.type, n.changed, n.nid, u.name ORDER BY last_activity DESC", 0, 15);
   }
 
   while ($node = db_fetch_object($sresult)) {
-    $output .= format_plural($node->comments, "1 comment", "%count comments") ." ". t("attached to node") ." ". l($node->title, "node/view/$node->nid") .":\n";
-
     if ($id) {
-      $cresult = db_query("SELECT c.*, u.name FROM comments c LEFT JOIN users u ON c.uid = u.uid WHERE c.timestamp > %d AND c.uid = '%d' AND c.nid = '%d' AND c.status = 0 ORDER BY cid DESC", $period, $id, $node->nid);
+      $cresult = db_query("SELECT c.*, u.name FROM comments c LEFT JOIN users u ON c.uid = u.uid WHERE c.timestamp > %d AND c.uid = '%d' AND c.nid = '%d' AND c.status = 0 ORDER BY cid DESC", time() - 259200, $id, $node->nid);
     }
     else {
-      $cresult = db_query("SELECT c.*, u.name FROM comments c LEFT JOIN users u ON c.uid = u.uid WHERE c.timestamp > %d AND c.nid = '%d'AND c.status = 0 ORDER BY cid DESC", $period, $node->nid);
+      $cresult = db_query("SELECT c.*, u.name FROM comments c LEFT JOIN users u ON c.uid = u.uid WHERE c.timestamp > %d AND c.nid = '%d' AND c.status = 0 ORDER BY cid DESC", time() - 259200, $node->nid);
     }
 
-    $output .= "<ul>";
+    $title = l($node->title, "node/view/$node->nid") ." ". (node_is_new($node->nid, $node->changed) ? theme("theme_mark") : "");
+    $type = module_invoke($node->type, "node", "name");
+
+    $comments = array();
     while ($comment = db_fetch_object($cresult)) {
-      $output .= " <li>". l($comment->subject, "node/view/$node->nid#$comment->cid") ." ". t("by") ." ". format_name($comment) ." (". t("replies") .": ". comment_num_replies($comment->cid) .") ". (comment_is_new($comment) ? theme("theme_mark") : "") ."</li>\n";
+      $comments[] = "<li>". l($comment->subject, "node/view/$node->nid#$comment->cid") ." ". t("by") ." ". format_name($comment) ." ". (node_is_new($comment->nid, $comment->timestamp) ? theme("theme_mark") : "") ."</li>\n";
+    }
+
+    $output .= "<p>". t("%type %title by %author", array("%type" => ucfirst($type), "%title" => $title, "%author" => format_name($node))) ."</p>";
+
+    if ($comments) {
+      $output .= "<ul>". implode("\n", $comments) ."</ul>";
     }
-    $output .= " </ul>\n";
   }
 
   return $output;
 }
 
-function tracker_menu() {
-  global $user;
-
-  $links[] = l(t("your recent comments"), "tracker/$user->uid", array("title" => t("Display an overview of your recent comments.")));
-  $links[] = l(t("all recent comments"), "tracker", array("title" => t("Display an overview of all the recent comments.")));
-
-  return "<div align=\"center\">". implode(" &middot; ", $links) ."</div>";
+function tracker_user($type, &$edit, &$user) {
+  switch ($type) {
+    case "view_public":
+      if (user_access("access content")) {
+        return form_item(t("Recent posts"), l(t("view recent posts"), "tracker/$user->uid"));
+      }
+  }
 }
 
-
 function tracker_page() {
   global $user;
 
-  if (user_access("access comments")) {
-    if (arg(1) == $user->uid) {
-      theme("header", t("Your recent comments"));
-      theme("box", t("Tracker"), tracker_menu());
-      theme("box", t("Your recent comments"), tracker_comments(arg(1)));
-      theme("footer");
-    }
-    else if (arg(1)) {
-      $account = user_load(array("uid" => arg(1)));
-      theme("header", t("%u's recent comments", array("%u" => $account->name)));
-      theme("box", t("Tracker"), tracker_menu());
-      theme("box", t("%u's recent comments", array("%u" => $account->name)), tracker_comments(arg(1)));
-      theme("footer");
-    }
-    else {
-      theme("header", t("All recent comments"));
-      theme("box", t("Tracker"), tracker_menu());
-      theme("box", t("All recent comments"), tracker_comments());
-      theme("footer");
-    }
+  if (user_access("access content")) {
+    theme("header", t("Recent activity"));
+    theme("box", t("Recent activity"), tracker_posts(arg(1)));
+    theme("footer");
   }
 }
 
-function tracker_user($type, &$edit, &$user) {
-  switch ($type) {
-    case "view_public":
-    case "view_private":
-      if (user_access("access comments")) {
-        return form_item(t("Comments"), l(t("view recent comments"), "tracker/$user->uid", array("title" => t("View recent comments."))));
-      }
-  }
-}
 ?>
diff --git a/modules/tracker/tracker.module b/modules/tracker/tracker.module
index e0ea2f9a0b42..f7563ab4de9f 100644
--- a/modules/tracker/tracker.module
+++ b/modules/tracker/tracker.module
@@ -2,103 +2,76 @@
 // $Id$
 
 function tracker_help() {
-  $output .= "<p>The tracker module is a handy module for displaying the most recent comments happenning all over your web site.  By following the <i>view new comments</i> link in the user block, a user may quickly review all recent comments.  When a user first arrives at the main tracker page, she sees all recent comments in reverse chronological order, grouped by post.  In addition, a self-centered user may choose to display only his own comments.</p>";
+  $output .= "<p>The tracker module is a handy module for displaying the most recent posts.  By following the <i>view recent posts</i> link in the user block, a user may quickly review all recent postings.</p>";
   return $output;
 }
 
 function tracker_system($field){
-  $system["description"] = t("Enables tracking of recent and new comments for users.");
+  $system["description"] = t("Enables tracking of recent posts for users.");
   return $system[$field];
 }
 
 function tracker_link($type) {
 
-  if ($type == "menu.view" && user_access("access comments")) {
-    $links[] = l(t("view new comments"), "tracker", array("title" => t("Display an overview of the recent comments.")));
+  if ($type == "menu.view" && user_access("access content")) {
+    $links[] = l(t("view recent posts"), "tracker", array("title" => t("Display an overview of the recent posts.")));
   }
 
   return $links ? $links : array();
 }
 
-function tracker_settings() {
-  $period = array(3600 => format_interval(3600), 10800 => format_interval(10800), 21600 => format_interval(21600), 32400 => format_interval(32400), 43200 => format_interval(43200), 86400 => format_interval(86400), 172800 => format_interval(172800), 259200 => format_interval(259200), 604800 => format_interval(604800), 1209600 => format_interval(1209600), 2419200 => format_interval(2419200), 1000000000 => "All");
-  $output .= form_select("Show comments more recent than", "tracker_period", variable_get("tracker_period", 259200), $period, "Comments younger than this get displayed.");
-  return $output;
-}
-
-function tracker_comments($id = 0) {
-  $period = time() - variable_get("tracker_period", 259200);  // all comments of the past 3 days if not configured to a different value
+function tracker_posts($id = 0) {
 
   if ($id) {
-    $sresult = db_query("SELECT n.nid, n.title, COUNT(n.nid) AS comments, MAX(c.timestamp) AS last_comment FROM comments c LEFT JOIN node n ON c.nid = n.nid WHERE c.status = 0 AND c.timestamp > $period AND c.uid = '%s' GROUP BY n.nid, n.title ORDER BY last_comment DESC LIMIT 10", $id);
+    $sresult = db_query_range("SELECT n.nid, n.title, n.type, n.changed, n.uid, u.name, GREATEST(n.changed, c.timestamp) AS last_activity FROM node n LEFT JOIN comments c ON n.nid = c.nid LEFT JOIN users u ON n.uid = u.uid WHERE n.uid = '". check_query($id) ."' AND n.status = 1 GROUP BY n.nid, n.title, n.type, n.changed, n.nid, u.name ORDER BY last_activity DESC", 0, 15);
   }
   else {
-    $sresult = db_query("SELECT n.nid, n.title, COUNT(n.nid) AS comments, MAX(c.timestamp) AS last_comment FROM comments c LEFT JOIN node n ON c.nid = n.nid WHERE c.status = 0 AND c.timestamp > $period GROUP BY n.nid, n.title ORDER BY last_comment DESC LIMIT 10");
+    $sresult = db_query_range("SELECT n.nid, n.title, n.type, n.changed, n.uid, u.name, GREATEST(n.changed, c.timestamp) AS last_activity FROM node n LEFT JOIN comments c ON n.nid = c.nid LEFT JOIN users u ON n.uid = u.uid WHERE n.status = 1 GROUP BY n.nid, n.title, n.type, n.changed, n.nid, u.name ORDER BY last_activity DESC", 0, 15);
   }
 
   while ($node = db_fetch_object($sresult)) {
-    $output .= format_plural($node->comments, "1 comment", "%count comments") ." ". t("attached to node") ." ". l($node->title, "node/view/$node->nid") .":\n";
-
     if ($id) {
-      $cresult = db_query("SELECT c.*, u.name FROM comments c LEFT JOIN users u ON c.uid = u.uid WHERE c.timestamp > %d AND c.uid = '%d' AND c.nid = '%d' AND c.status = 0 ORDER BY cid DESC", $period, $id, $node->nid);
+      $cresult = db_query("SELECT c.*, u.name FROM comments c LEFT JOIN users u ON c.uid = u.uid WHERE c.timestamp > %d AND c.uid = '%d' AND c.nid = '%d' AND c.status = 0 ORDER BY cid DESC", time() - 259200, $id, $node->nid);
     }
     else {
-      $cresult = db_query("SELECT c.*, u.name FROM comments c LEFT JOIN users u ON c.uid = u.uid WHERE c.timestamp > %d AND c.nid = '%d'AND c.status = 0 ORDER BY cid DESC", $period, $node->nid);
+      $cresult = db_query("SELECT c.*, u.name FROM comments c LEFT JOIN users u ON c.uid = u.uid WHERE c.timestamp > %d AND c.nid = '%d' AND c.status = 0 ORDER BY cid DESC", time() - 259200, $node->nid);
     }
 
-    $output .= "<ul>";
+    $title = l($node->title, "node/view/$node->nid") ." ". (node_is_new($node->nid, $node->changed) ? theme("theme_mark") : "");
+    $type = module_invoke($node->type, "node", "name");
+
+    $comments = array();
     while ($comment = db_fetch_object($cresult)) {
-      $output .= " <li>". l($comment->subject, "node/view/$node->nid#$comment->cid") ." ". t("by") ." ". format_name($comment) ." (". t("replies") .": ". comment_num_replies($comment->cid) .") ". (comment_is_new($comment) ? theme("theme_mark") : "") ."</li>\n";
+      $comments[] = "<li>". l($comment->subject, "node/view/$node->nid#$comment->cid") ." ". t("by") ." ". format_name($comment) ." ". (node_is_new($comment->nid, $comment->timestamp) ? theme("theme_mark") : "") ."</li>\n";
+    }
+
+    $output .= "<p>". t("%type %title by %author", array("%type" => ucfirst($type), "%title" => $title, "%author" => format_name($node))) ."</p>";
+
+    if ($comments) {
+      $output .= "<ul>". implode("\n", $comments) ."</ul>";
     }
-    $output .= " </ul>\n";
   }
 
   return $output;
 }
 
-function tracker_menu() {
-  global $user;
-
-  $links[] = l(t("your recent comments"), "tracker/$user->uid", array("title" => t("Display an overview of your recent comments.")));
-  $links[] = l(t("all recent comments"), "tracker", array("title" => t("Display an overview of all the recent comments.")));
-
-  return "<div align=\"center\">". implode(" &middot; ", $links) ."</div>";
+function tracker_user($type, &$edit, &$user) {
+  switch ($type) {
+    case "view_public":
+      if (user_access("access content")) {
+        return form_item(t("Recent posts"), l(t("view recent posts"), "tracker/$user->uid"));
+      }
+  }
 }
 
-
 function tracker_page() {
   global $user;
 
-  if (user_access("access comments")) {
-    if (arg(1) == $user->uid) {
-      theme("header", t("Your recent comments"));
-      theme("box", t("Tracker"), tracker_menu());
-      theme("box", t("Your recent comments"), tracker_comments(arg(1)));
-      theme("footer");
-    }
-    else if (arg(1)) {
-      $account = user_load(array("uid" => arg(1)));
-      theme("header", t("%u's recent comments", array("%u" => $account->name)));
-      theme("box", t("Tracker"), tracker_menu());
-      theme("box", t("%u's recent comments", array("%u" => $account->name)), tracker_comments(arg(1)));
-      theme("footer");
-    }
-    else {
-      theme("header", t("All recent comments"));
-      theme("box", t("Tracker"), tracker_menu());
-      theme("box", t("All recent comments"), tracker_comments());
-      theme("footer");
-    }
+  if (user_access("access content")) {
+    theme("header", t("Recent activity"));
+    theme("box", t("Recent activity"), tracker_posts(arg(1)));
+    theme("footer");
   }
 }
 
-function tracker_user($type, &$edit, &$user) {
-  switch ($type) {
-    case "view_public":
-    case "view_private":
-      if (user_access("access comments")) {
-        return form_item(t("Comments"), l(t("view recent comments"), "tracker/$user->uid", array("title" => t("View recent comments."))));
-      }
-  }
-}
 ?>
-- 
GitLab