diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 7b6eda4..78685a8 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -1477,12 +1477,12 @@ function comment_load($cid, $reset = FALSE) { function comment_num_new($nid, $timestamp = 0) { global $user; - if ($user->uid) { + if ($user->uid && module_exists('history')) { // Retrieve the timestamp at which the current user last viewed this node. if (!$timestamp) { - $timestamp = node_last_viewed($nid); + $timestamp = history_node_last_viewed($nid); } - $timestamp = ($timestamp > NODE_NEW_LIMIT ? $timestamp : NODE_NEW_LIMIT); + $timestamp = ($timestamp > HISTORY_READ_LIMIT ? $timestamp : HISTORY_READ_LIMIT); // Use the timestamp to retrieve the number of new comments. return db_query('SELECT COUNT(cid) FROM {comment} WHERE nid = :nid AND created > :timestamp AND status = :status', array( diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php index e1dcbec..c1eff57 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php @@ -141,8 +141,8 @@ function setEnvironment(array $info) { comment_save($comment); $this->comment = $comment; - // comment_num_new() relies on node_last_viewed(), so ensure that no one - // has seen the node of this comment. + // comment_num_new() relies on history_node_last_viewed(), so ensure + // that no one has seen the node of this comment. db_delete('history')->condition('nid', $this->node->nid)->execute(); } else { diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php index e8bab5d..902dbdd 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php @@ -20,7 +20,7 @@ * * @var array */ - public static $modules = array('comment', 'node'); + public static $modules = array('comment', 'node', 'history'); /** * An administrative user with permission to configure comment settings. diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTokenReplaceTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTokenReplaceTest.php index 34674e8..46db533 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTokenReplaceTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTokenReplaceTest.php @@ -11,6 +11,7 @@ * Tests comment token replacement in strings. */ class CommentTokenReplaceTest extends CommentTestBase { + public static function getInfo() { return array( 'name' => 'Comment token replacement', diff --git a/core/modules/forum/forum.info b/core/modules/forum/forum.info index 887ed93..c348a2a 100644 --- a/core/modules/forum/forum.info +++ b/core/modules/forum/forum.info @@ -1,6 +1,7 @@ name = Forum description = Provides discussion forums. dependencies[] = node +dependencies[] = history dependencies[] = taxonomy dependencies[] = comment package = Core diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module index 459cbeb..05960a0 100644 --- a/core/modules/forum/forum.module +++ b/core/modules/forum/forum.module @@ -873,7 +873,7 @@ function forum_forum_load($tid = NULL) { /** * Calculates the number of new posts in a forum that the user has not yet read. * - * Nodes are new if they are newer than NODE_NEW_LIMIT. + * Nodes are new if they are newer than HISTORY_READ_LIMIT. * * @param $term * The term ID of the forum. @@ -890,7 +890,7 @@ function _forum_topics_unread($term, $uid) { $query->addExpression('COUNT(n.nid)', 'count'); return $query ->condition('status', 1) - ->condition('n.created', NODE_NEW_LIMIT, '>') + ->condition('n.created', HISTORY_READ_LIMIT, '>') ->isNull('h.nid') ->addTag('node_access') ->execute() @@ -1311,7 +1311,7 @@ function template_preprocess_forum_submitted(&$variables) { * * @return * The timestamp when the user last viewed this node, if the user has - * previously viewed the node; otherwise NODE_NEW_LIMIT. + * previously viewed the node; otherwise HISTORY_READ_LIMIT. */ function _forum_user_last_visit($nid) { global $user; @@ -1320,10 +1320,10 @@ function _forum_user_last_visit($nid) { if (empty($history)) { $result = db_query('SELECT nid, timestamp FROM {history} WHERE uid = :uid', array(':uid' => $user->uid)); foreach ($result as $t) { - $history[$t->nid] = $t->timestamp > NODE_NEW_LIMIT ? $t->timestamp : NODE_NEW_LIMIT; + $history[$t->nid] = $t->timestamp > HISTORY_READ_LIMIT ? $t->timestamp : HISTORY_READ_LIMIT; } } - return isset($history[$nid]) ? $history[$nid] : NODE_NEW_LIMIT; + return isset($history[$nid]) ? $history[$nid] : HISTORY_READ_LIMIT; } /** diff --git a/core/modules/history/history.api.php b/core/modules/history/history.api.php new file mode 100644 index 0000000..0c7276e --- /dev/null +++ b/core/modules/history/history.api.php @@ -0,0 +1,6 @@ + 'A record of which {users} have read which {node}s.', + 'fields' => array( + 'uid' => array( + 'description' => 'The {users}.uid that read the {node} nid.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + 'nid' => array( + 'description' => 'The {node}.nid that was read.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + 'timestamp' => array( + 'description' => 'The Unix timestamp at which the read occurred.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('uid', 'nid'), + 'indexes' => array( + 'nid' => array('nid'), + ), + ); + + return $schema; +} diff --git a/core/modules/history/history.module b/core/modules/history/history.module new file mode 100644 index 0000000..953da8b --- /dev/null +++ b/core/modules/history/history.module @@ -0,0 +1,99 @@ +condition('timestamp', HISTORY_READ_LIMIT, '<') + ->execute(); +} + +/** + * Updates 'last viewed' timestamp of the specified entity for the current user. + * + * @param $nid + * The node ID that has been read. + * @param $account + * (optional) The user account to update the history for. Defaults to the + * current user. + */ +function history_update($nid, $account = NULL) { + global $user; + + if (!isset($account)) { + $account = $user; + } + + if ($account->uid) { + db_merge('history') + ->key(array( + 'uid' => $account->uid, + 'nid' => $nid, + )) + ->fields(array('timestamp' => REQUEST_TIME)) + ->execute(); + } +} + +/** + * Implements hook_node_delete(). + */ +function history_node_delete(Node $node) { + db_delete('history') + ->condition('nid', $node->nid) + ->execute(); +} + +/** + * Implements hook_user_cancel(). + */ +function history_user_cancel($edit, $account, $method) { + switch ($method) { + case 'user_cancel_reassign': + db_delete('history') + ->condition('uid', $account->uid) + ->execute(); + break; + } +} + +/** + * Retrieves the timestamp for the current user's last view of a specified node. + * + * @param int $nid + * A node ID. + * + * @return int + * If a node has been previously viewed by the user, the timestamp in seconds + * of when the last view occurred; otherwise, zero. + */ +function history_node_last_viewed($nid) { + global $user; + $history = &drupal_static(__FUNCTION__, array()); + + if (!isset($history[$nid])) { + $history[$nid] = db_query("SELECT timestamp FROM {history} WHERE uid = :uid AND nid = :nid", array(':uid' => $user->uid, ':nid' => $nid))->fetchObject(); + } + + return (isset($history[$nid]->timestamp) ? $history[$nid]->timestamp : 0); +} diff --git a/core/modules/history/history.views.inc b/core/modules/history/history.views.inc new file mode 100644 index 0000000..8597cfc --- /dev/null +++ b/core/modules/history/history.views.inc @@ -0,0 +1,47 @@ + array( + 'table' => 'history', + 'left_field' => 'nid', + 'field' => 'nid', + 'extra' => array( + array('field' => 'uid', 'value' => '***CURRENT_USER***', 'numeric' => TRUE), + ), + ), + ); + + $data['history']['timestamp'] = array( + 'title' => t('Has new content'), + 'field' => array( + 'id' => 'node_history_user_timestamp', + 'help' => t('Show a marker if the content is new or updated.'), + ), + 'filter' => array( + 'help' => t('Show only content that is new or updated.'), + 'id' => 'node_history_user_timestamp', + ), + ); + + return $data; +} diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php index 3993d24..1a56fe0 100644 --- a/core/modules/node/lib/Drupal/node/NodeStorageController.php +++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php @@ -159,9 +159,6 @@ protected function postDelete($nodes) { // Delete values from other tables also referencing this node. $ids = array_keys($nodes); - db_delete('history') - ->condition('nid', $ids, 'IN') - ->execute(); db_delete('node_access') ->condition('nid', $ids, 'IN') ->execute(); diff --git a/core/modules/node/node.install b/core/modules/node/node.install index f9c30a5..c6fd7e6 100644 --- a/core/modules/node/node.install +++ b/core/modules/node/node.install @@ -406,36 +406,6 @@ function node_schema() { ), ); - $schema['history'] = array( - 'description' => 'A record of which {users} have read which {node}s.', - 'fields' => array( - 'uid' => array( - 'description' => 'The {users}.uid that read the {node} nid.', - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => TRUE, - 'default' => 0, - ), - 'nid' => array( - 'description' => 'The {node}.nid that was read.', - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => TRUE, - 'default' => 0, - ), - 'timestamp' => array( - 'description' => 'The Unix timestamp at which the read occurred.', - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - ), - ), - 'primary key' => array('uid', 'nid'), - 'indexes' => array( - 'nid' => array('nid'), - ), - ); - return $schema; } @@ -740,6 +710,15 @@ function node_update_8011() { } /** + * Enable History module. + */ +function node_update_8012() { + // Enable the history module without re-installing the schema. + update_module_enable(array('history')); +} + + +/** * @} End of "addtogroup updates-7.x-to-8.x" * The next series of updates should start at 9000. */ diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 0b1306a..9575911 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -51,15 +51,6 @@ const NODE_STICKY = 1; /** - * Denotes the time cutoff for nodes marked as read. - * - * Nodes changed before this time are always marked as read. Nodes changed after - * this time may be marked new, updated, or read, depending on their state for - * the current user. Defaults to 30 days ago. - */ -define('NODE_NEW_LIMIT', REQUEST_TIME - 30 * 24 * 60 * 60); - -/** * Denotes that access is allowed for a node. * * Modules should return this value from hook_node_access() to allow access to a @@ -183,15 +174,6 @@ function node_theme() { } /** - * Implements hook_cron(). - */ -function node_cron() { - db_delete('history') - ->condition('timestamp', NODE_NEW_LIMIT, '<') - ->execute(); -} - -/** * Implements hook_entity_info_alter(). */ function node_entity_info_alter(&$info) { @@ -302,46 +284,6 @@ function node_title_list($result, $title = NULL) { } /** - * Updates the 'last viewed' timestamp of the specified node for current user. - * - * @param Drupal\node\Node $node - * A node entity. - */ -function node_tag_new(Node $node) { - global $user; - if ($user->uid) { - db_merge('history') - ->key(array( - 'uid' => $user->uid, - 'nid' => $node->nid, - )) - ->fields(array('timestamp' => REQUEST_TIME)) - ->execute(); - } -} - -/** - * Retrieves the timestamp for the current user's last view of a specified node. - * - * @param int $nid - * A node ID. - * - * @return int - * If a node has been previously viewed by the user, the timestamp in seconds - * of when the last view occurred; otherwise, zero. - */ -function node_last_viewed($nid) { - global $user; - $history = &drupal_static(__FUNCTION__, array()); - - if (!isset($history[$nid])) { - $history[$nid] = db_query("SELECT timestamp FROM {history} WHERE uid = :uid AND nid = :nid", array(':uid' => $user->uid, ':nid' => $nid))->fetchObject(); - } - - return (isset($history[$nid]->timestamp) ? $history[$nid]->timestamp : 0); -} - -/** * Decides on the type of marker to be displayed for a given node. * * @param $nid @@ -356,16 +298,17 @@ function node_mark($nid, $timestamp) { global $user; $cache = &drupal_static(__FUNCTION__, array()); - if (!$user->uid) { + $history_module_enabled = module_exists('history'); + if (!$user->uid || !$history_module_enabled) { return MARK_READ; } - if (!isset($cache[$nid])) { - $cache[$nid] = node_last_viewed($nid); + if (!isset($cache[$nid]) && $history_module_enabled) { + $cache[$nid] = history_node_last_viewed($nid); } - if ($cache[$nid] == 0 && $timestamp > NODE_NEW_LIMIT) { + if ($cache[$nid] == 0 && $timestamp > HISTORY_READ_LIMIT) { return MARK_NEW; } - elseif ($timestamp > $cache[$nid] && $timestamp > NODE_NEW_LIMIT) { + elseif ($timestamp > $cache[$nid] && $timestamp > HISTORY_READ_LIMIT) { return MARK_UPDATED; } return MARK_READ; @@ -1111,7 +1054,9 @@ function node_show(Node $node, $message = FALSE) { $nodes = array('nodes' => node_view_multiple(array($node->nid => $node), 'full')); // Update the history table, stating that this user viewed this node. - node_tag_new($node); + if (module_exists('history')) { + history_update($node->nid); + } return $nodes; } @@ -1494,10 +1439,6 @@ function node_user_cancel($edit, $account, $method) { ->fields(array('uid' => 0)) ->condition('uid', $account->uid) ->execute(); - // Clean history. - db_delete('history') - ->condition('uid', $account->uid) - ->execute(); break; } } @@ -1519,10 +1460,6 @@ function node_user_predelete($account) { foreach ($revisions as $revision) { node_revision_delete($revision); } - // Clean history. - db_delete('history') - ->condition('uid', $account->uid) - ->execute(); } /** diff --git a/core/modules/node/node.views.inc b/core/modules/node/node.views.inc index bf30614..3a396bb 100644 --- a/core/modules/node/node.views.inc +++ b/core/modules/node/node.views.inc @@ -640,37 +640,6 @@ function node_views_data() { ), ); - // History table - - // We're actually defining a specific instance of the table, so let's - // alias it so that we can later add the real table for other purposes if we - // need it. - $data['history']['table']['group'] = t('Content'); - - // Explain how this table joins to others. - $data['history']['table']['join'] = array( - // Directly links to node table. - 'node' => array( - 'table' => 'history', - 'left_field' => 'nid', - 'field' => 'nid', - 'extra' => array( - array('field' => 'uid', 'value' => '***CURRENT_USER***', 'numeric' => TRUE), - ), - ), - ); - - $data['history']['timestamp'] = array( - 'title' => t('Has new content'), - 'field' => array( - 'id' => 'node_history_user_timestamp', - 'help' => t('Show a marker if the content is new or updated.'), - ), - 'filter' => array( - 'help' => t('Show only content that is new or updated.'), - 'id' => 'node_history_user_timestamp', - ), - ); return $data; } diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php index c53d225..a1c151a 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php @@ -134,11 +134,11 @@ function testModuleEnableOrder() { $this->assertModules(array('module_test'), TRUE); variable_set('dependency_test', 'dependency'); // module_test creates a dependency chain: - // - forum depends on taxonomy, comment, and poll (via module_test) + // - forum depends on taxonomy, comment, history, and poll (via module_test) // - taxonomy depends on options // - poll depends on php (via module_test) // The correct enable order is: - $expected_order = array('comment', 'options', 'taxonomy', 'php', 'poll', 'forum'); + $expected_order = array('comment', 'history', 'options', 'taxonomy', 'php', 'poll', 'forum'); // Enable the modules through the UI, verifying that the dependency chain // is correct. @@ -146,14 +146,15 @@ function testModuleEnableOrder() { $edit['modules[Core][forum][enable]'] = 'forum'; $this->drupalPost('admin/modules', $edit, t('Save configuration')); $this->assertModules(array('forum'), FALSE); - $this->assertText(t('You must enable the Taxonomy, Options, Comment, Poll, PHP Filter modules to install Forum.')); + $this->assertText(t('You must enable the History, Taxonomy, Options, Comment, Poll, PHP Filter modules to install Forum.')); + $edit['modules[Core][history][enable]'] = 'history'; $edit['modules[Core][options][enable]'] = 'options'; $edit['modules[Core][taxonomy][enable]'] = 'taxonomy'; $edit['modules[Core][comment][enable]'] = 'comment'; $edit['modules[Core][poll][enable]'] = 'poll'; $edit['modules[Core][php][enable]'] = 'php'; $this->drupalPost('admin/modules', $edit, t('Save configuration')); - $this->assertModules(array('forum', 'poll', 'php', 'comment', 'taxonomy', 'options'), TRUE); + $this->assertModules(array('forum', 'poll', 'php', 'comment', 'history', 'taxonomy', 'options'), TRUE); // Check the actual order which is saved by module_test_modules_enabled(). $this->assertIdentical(variable_get('test_module_enable_order', array()), $expected_order); diff --git a/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php b/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php index 0473d38..189b927 100644 --- a/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php +++ b/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php @@ -19,7 +19,7 @@ class TrackerTest extends WebTestBase { * * @var array */ - public static $modules = array('comment', 'tracker'); + public static $modules = array('comment', 'tracker', 'history'); /** * The main user for testing. diff --git a/core/modules/user/user.api.php b/core/modules/user/user.api.php index 8a21ef2..9401476 100644 --- a/core/modules/user/user.api.php +++ b/core/modules/user/user.api.php @@ -126,10 +126,6 @@ function hook_user_cancel($edit, $account, $method) { ->fields(array('uid' => 0)) ->condition('uid', $account->uid) ->execute(); - // Clean history. - db_delete('history') - ->condition('uid', $account->uid) - ->execute(); break; } } diff --git a/core/profiles/standard/standard.info b/core/profiles/standard/standard.info index 4c812d0..9747bd5 100644 --- a/core/profiles/standard/standard.info +++ b/core/profiles/standard/standard.info @@ -3,6 +3,7 @@ description = Install with commonly used features pre-configured. version = VERSION core = 8.x dependencies[] = node +dependencies[] = history dependencies[] = block dependencies[] = color dependencies[] = config