--- ./database/database.mysql 2004/03/14 17:07:31 1.1.1.1 +++ ./database/database.mysql 2004/03/14 17:12:39 @@ -133,6 +133,17 @@ ) TYPE=MyISAM; -- +-- Table structure for table `comments_history` +-- + +CREATE TABLE comments_history ( + uid int(10) NOT NULL default '0', + min_cid int(10) NOT NULL default '0', + max_cid int(10) NOT NULL default '0', + KEY (uid) +) TYPE=MyISAM; + +-- -- Table structure for table 'directory' -- --- ./modules/forum.module 2004/03/14 17:07:31 1.1.1.1 +++ ./modules/forum.module 2004/03/14 20:36:19 @@ -308,14 +312,42 @@ return db_result(db_query("SELECT COUNT(*) AS count FROM {comments} c INNER JOIN {node} n ON n.nid = c.nid INNER JOIN {forum} f ON n.nid = f.nid WHERE f.tid = %d AND n.nid = f.nid AND n.nid = c.nid AND n.status = 1 AND c.status = 0 AND n.type = 'forum'", $term)); } -function _forum_topics_read($term, $uid) { - // Calculate the number of topics the user has read. Assume all entries older - // than NODE_NEW_LIMIT are read, and include the recent posts that user has - // read. - $ancient = db_result(db_query('SELECT COUNT(*) FROM {forum} f INNER JOIN {node} n ON f.nid = n.nid WHERE f.tid = %d AND n.status = 1 AND n.created <= %d AND f.shadow = 0', $term, NODE_NEW_LIMIT)); - $recent = db_result(db_query('SELECT COUNT(*) FROM {forum} f INNER JOIN {node} n ON f.nid = n.nid INNER JOIN {history} h ON n.nid = h.nid WHERE n.status = 1 AND f.tid = %d AND h.uid = %d AND n.created > %d AND f.shadow = 0', $term, $uid, NODE_NEW_LIMIT)); +function _forum_topics_unread($term, $uid) { + // Find the unread topics in each forum, or in only the specified + // forum if one is specified. The unread topics must have been + // created since NODE_NEW_LIMIT or have unread comments created + // since NODE_NEW_LIMIT and and must not have been marked read in + // the history table. Return a nested array of tids, nids and + // timestamps (indicating how new the topic should be considered). + + // First find new topics - return $ancient + $recent; + $query_string = 'SELECT f.tid, f.nid, n.created FROM {forum} f INNER JOIN {node} n ON f.nid = n.nid LEFT JOIN {history} h ON n.nid = h.nid AND h.uid = %d WHERE n.status = 1 AND h.uid IS NULL AND n.created > %d AND f.shadow = 0'; + if ($term) { + $query_string .= ' AND f.tid = %d'; + } + $result = db_query($query_string, $uid, NODE_NEW_LIMIT, $term); + + while ($obj = db_fetch_object($result)) { + $unread[$obj->tid][$obj->nid] = $obj->created; + } + + // Now find topics with new comments + + $query_string = 'SELECT f.tid, c.nid, c.timestamp FROM {comments} c LEFT JOIN {comments_history} h ON h.uid = %d AND c.cid >= h.min_cid AND c.cid <= h.max_cid'; + if ($term) { + $query_string .= sprintf(' AND f.tid = %d', $term); + } + $query_string .= ' INNER JOIN {forum} f ON c.nid = f.nid WHERE c.status = 0 AND h.min_cid IS NULL AND f.shadow = 0 and c.timestamp > %d GROUP BY tid, nid'; + $result = db_query($query_string, $uid, NODE_NEW_LIMIT); + + while ($obj = db_fetch_object($result)) { + if (! $unread[$obj->tid][$obj->nid]) { + $unread[$obj->tid][$obj->nid] = $obj->timestamp; + } + } + + return $unread ? $unread : array(); } function _forum_last_post($term) { @@ -370,7 +402,7 @@ $topic->new = 0; } else { - $topic->new_replies = db_result(db_query('SELECT COUNT(c.nid) FROM {node} n INNER JOIN {comments} c ON n.nid = c.nid WHERE n.nid = %d AND n.status = 1 AND c.status = 0 AND c.timestamp > %d', $topic->nid, $history)); + $topic->new_replies = comment_num_new($topic->nid); $topic->new = $topic->new_replies || ($topic->timestamp > $history); } } @@ -387,16 +419,22 @@ return $topics; } -function _forum_new($tid) { +function _forum_new($tid, $exclude = 0) { global $user; - $result = db_query("SELECT n.nid FROM {node} n, {history} h, {forum} f WHERE n.type = 'forum' AND n.status = 1 AND h.nid = n.nid AND f.nid = h.nid AND f.tid = %d AND h.uid = %d", $tid, $user->uid); - while ($r = db_fetch_object($result)) { - $read[] = $r->nid; - } + $read = _forum_topics_unread($tid, $user->uid); + $read = $read[$tid]; - $nid = db_result(db_query_range("SELECT n.nid FROM {node} n INNER JOIN {forum} f ON n.nid = f.nid WHERE n.type = 'forum' AND f.nid = n.nid AND n.status = 1 AND f.tid = %d ". ($read ? "AND NOT (n.nid IN (". implode(',', $read) .")) " : '') ."ORDER BY created", $tid, 0, 1)); + if ($read) { + asort($read, SORT_NUMERIC); + + foreach ($read as $nid => $timestamp) { + if (! $exclude || ($nid != $exclude)) { + return $nid; + } + } + } - return $nid ? $nid : 0; + return 0; } function forum_page() { @@ -513,6 +551,10 @@ $header = array(t('Forum'), t('Topics'), t('Posts'), t('Last post')); + if ($user->uid) { + $unread = _forum_topics_unread(0, $user->uid); + } + foreach ($forums as $forum) { if ($forum->container) { $description = "
depth * 30) ."px;\">\n"; @@ -526,13 +568,13 @@ $rows[] = array(array('data' => $description, 'class' => 'container', 'colspan' => 4)); } else { - $forum->old_topics = _forum_topics_read($forum->tid, $user->uid); if ($user->uid) { - $new_topics = $forum->num_topics - $forum->old_topics; + $new_topics = count($unread[$forum->tid]); } else { $new_topics = 0; } + $forum->old_topics = $forum->num_topics - $new_topics; $links = array(); --- ./modules/comment.module 2004/03/14 17:07:31 1.1.1.1 +++ ./modules/comment.module 2004/03/15 01:13:37 @@ -644,7 +654,7 @@ */ if ($order == 1) { - if ($mode == 1 || $mode == 2) { + if ($mode == 1 || $mode == 2 || $mode == 5) { $query .= " ORDER BY c.timestamp DESC"; } else { @@ -652,7 +662,7 @@ } } else if ($order == 2) { - if ($mode == 1 || $mode == 2) { + if ($mode == 1 || $mode == 2 || $mode == 5) { $query .= " ORDER BY c.timestamp"; } else { @@ -684,6 +694,7 @@ while ($comment = db_fetch_object($result)) { $comment = drupal_unpack($comment); + $comment->new = comment_is_new($comment->cid); $comment->depth = count(explode(".", $comment->thread)) - 1; if ($mode == 1) { @@ -692,12 +703,18 @@ else if ($mode == 2) { $output .= theme("comment_flat_expanded", $comment, $threshold_min); } + else if ($mode == 5) { + $output .= theme("comment_flat_new_expanded", $comment, $threshold_min); + } else if ($mode == 3) { $output .= theme("comment_thread_min", $comment, $threshold_min); } else if ($mode == 4) { $output .= theme("comment_thread_max", $comment, $threshold_min); } + else if ($mode == 6) { + $output .= theme("comment_thread_new_max", $comment, $threshold_min); + } } /* @@ -984,7 +1006,7 @@ $result = pager_query($sql, 50); while ($comment = db_fetch_object($result)) { - $rows[] = array(l($comment->subject, "node/view/$comment->nid/$comment->cid", array("title" => htmlspecialchars(substr($comment->comment, 0, 128))), NULL, "comment-$comment->cid") ." ". (node_is_new($comment->nid, $comment->timestamp) ? theme("mark") : ""), format_name($comment), ($comment->status == 0 ? t("published") : t("not published")) ."". format_date($comment->timestamp, "small") ."". 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", array("title" => htmlspecialchars(substr($comment->comment, 0, 128))), NULL, "comment-$comment->cid") ." ". (comment_is_new($comment->cid) ? theme("mark") : ""), format_name($comment), ($comment->status == 0 ? t("published") : t("not published")) ."". format_date($comment->timestamp, "small") ."". l(t("edit comment"), "admin/comment/edit/$comment->cid"), l(t("delete comment"), "admin/comment/delete/$comment->cid")); } if ($pager = theme("pager", NULL, 50, 0, tablesort_pager())) { @@ -1273,8 +1295,10 @@ ** Switch to folded/unfolded view of the comment */ $output = ""; - if (node_is_new($comment->nid, $comment->timestamp)) { - $comment->new = 1; + if (! isset($comment->new)) { + $comment->new = comment_is_new($comment->cid); + } + if ($comment->new) { $output .= "\n"; } @@ -1283,6 +1307,7 @@ if ($visible) { $comment->comment = check_output($comment->comment); $output .= theme("comment", $comment, $links); + comment_tag_new($comment->cid); } else { $output .= theme("comment_folded", $comment); @@ -1394,7 +1419,8 @@ $output .= "
". check_output($comment->comment) ."
"; $output .= "
$links
"; $output .= "
"; + comment_tag_new($comment->cid); return $output; } function theme_comment_folded($comment) { @@ -1408,8 +1438,14 @@ return ""; } -function theme_comment_flat_expanded($comment, $threshold) { - return theme("comment_view", $comment, theme('links', module_invoke_all('link', 'comment', $comment, 0)), comment_visible($comment, $threshold)); +function theme_comment_flat_expanded($comment, $threshold, $check_new = 0) { + $expand = comment_visible($comment, $threshold) && + ($check_new ? $comment->new : 1); + return theme("comment_view", $comment, theme('links', module_invoke_all('link', 'comment', $comment, 0)), $expand); +} + +function theme_comment_flat_new_expanded($comment, $threshold) { + return theme_comment_flat_expanded($comment, $treshold, 1); } function theme_comment_thread_min($comment, $threshold, $pid = 0) { @@ -1421,13 +1457,16 @@ return $output; } -function theme_comment_thread_max($comment, $threshold, $level = 0) { +function theme_comment_thread_max($comment, $threshold, $level = 0, $check_new = 0) { $output = ""; if ($comment->depth) { $output .= "
depth * 25) ."px;\">\n"; } - $output .= theme("comment_view", $comment, theme('links', module_invoke_all('link', 'comment', $comment, 0)), comment_visible($comment, $threshold)); + $expand = comment_visible($comment, $threshold) && + ($check_new ? $comment->new : 1); + + $output .= theme("comment_view", $comment, theme('links', module_invoke_all('link', 'comment', $comment, 0)), $expand); if ($comment->depth) { $output .= "
\n"; @@ -1435,6 +1474,10 @@ return $output; } +function theme_comment_thread_new_max($comment, $threshold, $level = 0) { + return theme_comment_thread_max($comment, $threshold, $level, 1); +} + function theme_comment_post_forbidden() { global $user; if ($user->uid) { @@ -1537,40 +1580,6 @@ return $cache[$pid]; } -/** - * 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) - */ -function comment_num_new($nid, $timestamp = 0) { - global $user; - - if ($user->uid) { - /* - ** Retrieve the timestamp at which the current user last viewed the - ** specified node. - */ - - if (!$timestamp) { - $timestamp = node_last_viewed($nid); - } - - /* - ** Use the timestamp to retrieve the number of new comments - */ - - $result = db_result(db_query("SELECT COUNT(c.cid) FROM {node} n INNER JOIN {comments} c ON n.nid = c.nid WHERE n.nid = %d AND timestamp > %d AND c.status = 0", $nid, $timestamp)); - - return $result; - } - else { - return 0; - } - -} - function comment_user_can_moderate($node) { global $user; return (user_access("moderate comments")); @@ -1669,7 +1678,7 @@ ** is not initialized yet when the comment module is loaded. */ - return array(1 => t("Flat list - collapsed"), 2 => t("Flat list - expanded"), 3 => t("Threaded list - collapsed"), 4 => t("Threaded list - expanded")); + return array(1 => t("Flat list - collapsed"), 2 => t("Flat list - expanded"), 5 => t("Flat list - new expanded"), 3 => t("Threaded list - collapsed"), 4 => t("Threaded list - expanded"), 6 => t("Threaded list - new expanded")); } function _comment_get_orders() { @@ -1680,6 +1689,106 @@ return array(1 => t("Date - newest first"), 2 => t("Date - oldest first")); } +function comment_tag_new($cid) { + global $user; + + if (! $user->uid) { + return; + } + + $result = db_query("SELECT uid FROM {comments_history} WHERE uid = %d AND min_cid <= %d and max_cid >= %d", $user->uid, $cid, $cid); + if (db_fetch_object($result)) { + return; + } + + db_query("UPDATE {comments_history} SET min_cid = %d where uid = %d AND min_cid = %d", $cid, $user->uid, $cid + 1); + if (db_affected_rows()) { + return; + } + + db_query("UPDATE {comments_history} SET max_cid = %d where uid = %d AND max_cid = %d", $cid, $user->uid, $cid - 1); + if (db_affected_rows()) { + return; + } + + db_query("INSERT INTO {comments_history} (uid, min_cid, max_cid) VALUES (%d, %d, %d)", $user->uid, $cid, $cid); +} + +function comment_is_new($cid) { + global $user; + + if (! $user->uid) { + return false; + } + + $result = db_query("SELECT * FROM {comments_history} where uid = %d and min_cid <= %d and max_cid >= %d", $user->uid, $cid, $cid); + if (db_fetch_object($result)) { + return false; + } + + return true; +} + +function comment_num_new($nid) { + global $user; + + if (! $user->uid) { + return 0; + } + + $result = db_result(db_query("SELECT COUNT(c.cid) FROM {comments} c LEFT JOIN {comments_history} h ON h.uid = %d AND c.cid >= h.min_cid AND c.cid <= h.max_cid WHERE c.nid = %d AND c.status = 0 AND h.min_cid IS NULL", $user->uid, $nid)); + + return $result; +} + +function comment_cron() { + $earliest = db_result(db_query('SELECT MIN(c.cid) FROM {comments} c WHERE c.timestamp > %d', NODE_NEW_LIMIT)); + db_query('DELETE FROM {comments} WHERE max_cid < %d', $earliest); + + $rows = db_query("SELECT * FROM {comments_history} ORDER BY uid, min_cid"); + + if (! ($row = db_fetch_object($rows))) { + return; + } + + $uid = $row->uid; + $min = $row->min_cid; + $max = $row->max_cid; + $updating = false; + + while ($row = db_fetch_object($rows)) { + if ($row->uid == $uid && $row->min_cid <= $max + 1) { + $updating = true; + $max = max($max, $row->max_cid); + continue; + } + if ($updating) { + $updates[] = array($uid, $min, $max); + } + $uid = $row->uid; + $min = $row->min_cid; + $max = $row->max_cid; + $updating = false; + } + + if ($updating) { + $updates[] = array($uid, $min, $max); + } + + if (! $updates) { + return; + } + + foreach ($updates as $update) { + $uid = $update[0]; + $min = $update[1]; + $max = $update[2]; + + db_query("INSERT INTO {comments_history} (uid, min_cid, max_cid) values (%d, %d, %d)", $uid, $min, $max); + db_query("DELETE FROM {comments_history} WHERE uid = %d AND (min_cid > %d and max_cid < %d) OR (min_cid = %d and max_cid < %d) OR (min_cid > %d AND max_cid = %d)", $uid, $min, $max, $min, $max, $min, $max); + } +} + function _comment_per_page() { return drupal_map_assoc(array(10, 30, 50, 70, 90)); }