Commit 465d86e2 authored by Dries's avatar Dries

Issue #1120928 by dagmar, sun, rootatwc, catch: Move 'history' table into separate History module.

parent 009ab352
......@@ -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_read($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(
......
......@@ -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_read(), so ensure that no one has
// seen the node of this comment.
db_delete('history')->condition('nid', $this->node->nid)->execute();
}
else {
......
......@@ -20,7 +20,7 @@ abstract class CommentTestBase extends WebTestBase {
*
* @var array
*/
public static $modules = array('comment', 'node');
public static $modules = array('comment', 'node', 'history');
/**
* An administrative user with permission to configure comment settings.
......
name = Forum
description = Provides discussion forums.
dependencies[] = node
dependencies[] = history
dependencies[] = taxonomy
dependencies[] = comment
package = Core
......
......@@ -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;
}
/**
......
<?php
/**
* @file
* API documentation for History module.
*/
name = History
description = Records which user has read which content.
package = Core
version = VERSION
core = 8.x
dependencies[] = node
<?php
/**
* @file
* Installation functions for History module.
*/
/**
* Implements hook_schema().
*/
function history_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',
'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;
}
<?php
/**
* @file
* Records which users has read which content.
*
* @todo
* - Generic helper for _forum_user_last_visit() + history_read().
* - Generic helper for node_mark().
*/
use Drupal\node\Plugin\Core\Entity\Node;
/**
* Entities changed before this time are always shown as read.
*
* Entities changed within this time may be marked as new, updated, or read,
* depending on their state for the current user. Defaults to 30 days ago.
*/
define('HISTORY_READ_LIMIT', REQUEST_TIME - 30 * 24 * 60 * 60);
/**
* 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_read($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);
}
/**
* 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_write($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_cron().
*/
function history_cron() {
db_delete('history')
->condition('timestamp', HISTORY_READ_LIMIT, '<')
->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;
}
}
/**
* Implements hook_user_delete().
*/
function history_user_delete($account) {
db_delete('history')
->condition('uid', $account->uid)
->execute();
}
<?php
/**
* @file
* Provide views data and handlers for history.module.
*
* @ingroup views_module_handlers
*/
/**
* Implements hook_views_data().
*/
function history_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;
}
......@@ -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();
......
......@@ -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;
}
......@@ -739,6 +709,15 @@ function node_update_8011() {
update_variables_to_state(array('node_cron_last' =>'node.cron_last'));
}
/**
* 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.
......
......@@ -50,15 +50,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.
*
......@@ -182,15 +173,6 @@ function node_theme() {
);
}
/**
* Implements hook_cron().
*/
function node_cron() {
db_delete('history')
->condition('timestamp', NODE_NEW_LIMIT, '<')
->execute();
}
/**
* Implements hook_entity_info().
*/
......@@ -301,46 +283,6 @@ function node_title_list($result, $title = NULL) {
return $num_rows ? array('#theme' => 'item_list__node', '#items' => $items, '#title' => $title) : FALSE;
}
/**
* 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.
*
......@@ -356,16 +298,16 @@ function node_mark($nid, $timestamp) {
global $user;
$cache = &drupal_static(__FUNCTION__, array());
if (!$user->uid) {
if (!$user->uid || !module_exists('history')) {
return MARK_READ;
}
if (!isset($cache[$nid])) {
$cache[$nid] = node_last_viewed($nid);
$cache[$nid] = history_read($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;
......@@ -1114,7 +1056,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_write($node->nid);
}
return $nodes;
}
......@@ -1503,10 +1447,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;
}
}
......@@ -1528,10 +1468,6 @@ function node_user_predelete($account) {
foreach ($revisions as $revision) {
node_revision_delete($revision);
}
// Clean history.
db_delete('history')
->condition('uid', $account->uid)
->execute();
}
/**
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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.
......
......@@ -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;
}
}
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment