Move into nested docroot
This commit is contained in:
parent
83a0d3a149
commit
c8b70abde9
13405 changed files with 0 additions and 0 deletions
|
@ -0,0 +1 @@
|
|||
cron_index_limit: 1000
|
|
@ -0,0 +1,9 @@
|
|||
# Schema for the configuration files of the tracker module.
|
||||
|
||||
tracker.settings:
|
||||
type: config_object
|
||||
label: 'Tracker settings'
|
||||
mapping:
|
||||
cron_index_limit:
|
||||
type: integer
|
||||
label: 'Cron index limit'
|
|
@ -0,0 +1,9 @@
|
|||
# Schema for the views plugins of the Tracker module.
|
||||
|
||||
views.argument.tracker_user_uid:
|
||||
type: views.argument.argument_comment_user_uid
|
||||
label: 'Nodes user posted/commented on'
|
||||
|
||||
views.filter.tracker_user_uid:
|
||||
type: views.filter.user_name
|
||||
label: 'UID of a nodes user posted/commented on'
|
122
web/core/modules/tracker/js/tracker-history.js
Normal file
122
web/core/modules/tracker/js/tracker-history.js
Normal file
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* Attaches behaviors for the Tracker module's History module integration.
|
||||
*
|
||||
* May only be loaded for authenticated users, with the History module enabled.
|
||||
*/
|
||||
(function ($, Drupal, window) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Render "new" and "updated" node indicators, as well as "X new" replies links.
|
||||
*/
|
||||
Drupal.behaviors.trackerHistory = {
|
||||
attach: function (context) {
|
||||
// Find all "new" comment indicator placeholders newer than 30 days ago that
|
||||
// have not already been read after their last comment timestamp.
|
||||
var nodeIDs = [];
|
||||
var $nodeNewPlaceholders = $(context)
|
||||
.find('[data-history-node-timestamp]')
|
||||
.once('history')
|
||||
.filter(function () {
|
||||
var nodeTimestamp = parseInt(this.getAttribute('data-history-node-timestamp'), 10);
|
||||
var nodeID = this.getAttribute('data-history-node-id');
|
||||
if (Drupal.history.needsServerCheck(nodeID, nodeTimestamp)) {
|
||||
nodeIDs.push(nodeID);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// Find all "new" comment indicator placeholders newer than 30 days ago that
|
||||
// have not already been read after their last comment timestamp.
|
||||
var $newRepliesPlaceholders = $(context)
|
||||
.find('[data-history-node-last-comment-timestamp]')
|
||||
.once('history')
|
||||
.filter(function () {
|
||||
var lastCommentTimestamp = parseInt(this.getAttribute('data-history-node-last-comment-timestamp'), 10);
|
||||
var nodeTimestamp = parseInt(this.previousSibling.previousSibling.getAttribute('data-history-node-timestamp'), 10);
|
||||
// Discard placeholders that have zero comments.
|
||||
if (lastCommentTimestamp === nodeTimestamp) {
|
||||
return false;
|
||||
}
|
||||
var nodeID = this.previousSibling.previousSibling.getAttribute('data-history-node-id');
|
||||
if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) {
|
||||
if (nodeIDs.indexOf(nodeID) === -1) {
|
||||
nodeIDs.push(nodeID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if ($nodeNewPlaceholders.length === 0 && $newRepliesPlaceholders.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the node read timestamps from the server.
|
||||
Drupal.history.fetchTimestamps(nodeIDs, function () {
|
||||
processNodeNewIndicators($nodeNewPlaceholders);
|
||||
processNewRepliesIndicators($newRepliesPlaceholders);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function processNodeNewIndicators($placeholders) {
|
||||
var newNodeString = Drupal.t('new');
|
||||
var updatedNodeString = Drupal.t('updated');
|
||||
|
||||
$placeholders.each(function (index, placeholder) {
|
||||
var timestamp = parseInt(placeholder.getAttribute('data-history-node-timestamp'), 10);
|
||||
var nodeID = placeholder.getAttribute('data-history-node-id');
|
||||
var lastViewTimestamp = Drupal.history.getLastRead(nodeID);
|
||||
|
||||
if (timestamp > lastViewTimestamp) {
|
||||
var message = (lastViewTimestamp === 0) ? newNodeString : updatedNodeString;
|
||||
$(placeholder).append('<span class="marker">' + message + '</span>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function processNewRepliesIndicators($placeholders) {
|
||||
// Figure out which placeholders need the "x new" replies links.
|
||||
var placeholdersToUpdate = {};
|
||||
$placeholders.each(function (index, placeholder) {
|
||||
var timestamp = parseInt(placeholder.getAttribute('data-history-node-last-comment-timestamp'), 10);
|
||||
var nodeID = placeholder.previousSibling.previousSibling.getAttribute('data-history-node-id');
|
||||
var lastViewTimestamp = Drupal.history.getLastRead(nodeID);
|
||||
|
||||
// Queue this placeholder's "X new" replies link to be downloaded from the
|
||||
// server.
|
||||
if (timestamp > lastViewTimestamp) {
|
||||
placeholdersToUpdate[nodeID] = placeholder;
|
||||
}
|
||||
});
|
||||
|
||||
// Perform an AJAX request to retrieve node view timestamps.
|
||||
var nodeIDs = Object.keys(placeholdersToUpdate);
|
||||
if (nodeIDs.length === 0) {
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
url: Drupal.url('comments/render_new_comments_node_links'),
|
||||
type: 'POST',
|
||||
data: {'node_ids[]': nodeIDs},
|
||||
dataType: 'json',
|
||||
success: function (results) {
|
||||
for (var nodeID in results) {
|
||||
if (results.hasOwnProperty(nodeID) && placeholdersToUpdate.hasOwnProperty(nodeID)) {
|
||||
var url = results[nodeID].first_new_comment_link;
|
||||
var text = Drupal.formatPlural(results[nodeID].new_comment_count, '1 new', '@count new');
|
||||
$(placeholdersToUpdate[nodeID]).append('<br /><a href="' + url + '">' + text + '</a>');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
})(jQuery, Drupal, window);
|
|
@ -0,0 +1,15 @@
|
|||
id: d7_tracker_node
|
||||
label: Tracker node
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
source:
|
||||
plugin: d7_tracker_node
|
||||
process:
|
||||
nid: nid
|
||||
published: published
|
||||
changed: changed
|
||||
destination:
|
||||
plugin: entity:node
|
||||
migration_dependencies:
|
||||
required:
|
||||
- d7_user
|
|
@ -0,0 +1,13 @@
|
|||
id: d7_tracker_settings
|
||||
label: Tracker settings
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- tracker_batch_size
|
||||
process:
|
||||
cron_index_limit: tracker_batch_size
|
||||
destination:
|
||||
plugin: config
|
||||
config_name: tracker.settings
|
|
@ -0,0 +1,16 @@
|
|||
id: d7_tracker_user
|
||||
label: Tracker user
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
source:
|
||||
plugin: d7_tracker_user
|
||||
process:
|
||||
nid: nid
|
||||
uid: uid
|
||||
published: published
|
||||
changed: changed
|
||||
destination:
|
||||
plugin: entity:user
|
||||
migration_dependencies:
|
||||
required:
|
||||
- d7_user
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Access;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\UserInterface;
|
||||
|
||||
/**
|
||||
* Access check for user tracker routes.
|
||||
*/
|
||||
class ViewOwnTrackerAccessCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* Checks access.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The currently logged in account.
|
||||
* @param \Drupal\user\UserInterface $user
|
||||
* The user whose tracker page is being accessed.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function access(AccountInterface $account, UserInterface $user) {
|
||||
return AccessResult::allowedIf($user && $account->isAuthenticated() && ($user->id() == $account->id()))->cachePerUser();
|
||||
}
|
||||
|
||||
}
|
20
web/core/modules/tracker/src/Controller/TrackerPage.php
Normal file
20
web/core/modules/tracker/src/Controller/TrackerPage.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
|
||||
/**
|
||||
* Controller for tracker.page route.
|
||||
*/
|
||||
class TrackerPage extends ControllerBase {
|
||||
|
||||
/**
|
||||
* Content callback for the tracker.page route.
|
||||
*/
|
||||
public function getContent() {
|
||||
module_load_include('inc', 'tracker', 'tracker.pages');
|
||||
return tracker_page();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\user\UserInterface;
|
||||
|
||||
/**
|
||||
* Controller for tracker.users_recent_content route.
|
||||
*/
|
||||
class TrackerUserRecent extends ControllerBase {
|
||||
|
||||
/**
|
||||
* Content callback for the tracker.users_recent_content route.
|
||||
*/
|
||||
public function getContent(UserInterface $user) {
|
||||
module_load_include('inc', 'tracker', 'tracker.pages');
|
||||
return tracker_page($user);
|
||||
}
|
||||
|
||||
}
|
28
web/core/modules/tracker/src/Controller/TrackerUserTab.php
Normal file
28
web/core/modules/tracker/src/Controller/TrackerUserTab.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\user\UserInterface;
|
||||
|
||||
/**
|
||||
* Controller for tracker.user_tab route.
|
||||
*/
|
||||
class TrackerUserTab extends ControllerBase {
|
||||
|
||||
/**
|
||||
* Content callback for the tracker.user_tab route.
|
||||
*/
|
||||
public function getContent(UserInterface $user) {
|
||||
module_load_include('inc', 'tracker', 'tracker.pages');
|
||||
return tracker_page($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Title callback for the tracker.user_tab route.
|
||||
*/
|
||||
public function getTitle(UserInterface $user) {
|
||||
return $user->getUsername();
|
||||
}
|
||||
|
||||
}
|
43
web/core/modules/tracker/src/Plugin/Menu/UserTrackerTab.php
Normal file
43
web/core/modules/tracker/src/Plugin/Menu/UserTrackerTab.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Plugin\Menu;
|
||||
|
||||
use Drupal\Core\Menu\LocalTaskDefault;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
|
||||
/**
|
||||
* Provides route parameters needed to link to the current user tracker tab.
|
||||
*/
|
||||
class UserTrackerTab extends LocalTaskDefault {
|
||||
|
||||
/**
|
||||
* Current user object.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Gets the current active user.
|
||||
*
|
||||
* @todo: https://www.drupal.org/node/2105123 put this method in
|
||||
* \Drupal\Core\Plugin\PluginBase instead.
|
||||
*
|
||||
* @return \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected function currentUser() {
|
||||
if (!$this->currentUser) {
|
||||
$this->currentUser = \Drupal::currentUser();
|
||||
}
|
||||
return $this->currentUser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRouteParameters(RouteMatchInterface $route_match) {
|
||||
return array('user' => $this->currentUser()->Id());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Drupal 7 tracker node source from database.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_tracker_node",
|
||||
* source_provider = "tracker"
|
||||
* )
|
||||
*/
|
||||
class TrackerNode extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
return $this->select('tracker_node', 'tn')->fields('tn');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'nid' => $this->t('The {node}.nid this record tracks.'),
|
||||
'published' => $this->t('Boolean indicating whether the node is published.'),
|
||||
'changed' => $this->t('The Unix timestamp when the node was most recently saved or commented on.'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['nid']['type'] = 'integer';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Drupal 7 tracker user source from database.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_tracker_user",
|
||||
* source_provider = "tracker"
|
||||
* )
|
||||
*/
|
||||
class TrackerUser extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
return $this->select('tracker_user', 'tu')->fields('tu');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'nid' => $this->t('The {user}.nid this record tracks.'),
|
||||
'uid' => $this->t('The {users}.uid of the node author or commenter.'),
|
||||
'published' => $this->t('Boolean indicating whether the node is published.'),
|
||||
'changed' => $this->t('The Unix timestamp when the user was most recently saved or commented on.'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['nid']['type'] = 'integer';
|
||||
$ids['uid']['type'] = 'integer';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Plugin\views\argument;
|
||||
|
||||
use Drupal\comment\Plugin\views\argument\UserUid as CommentUserUid;
|
||||
|
||||
/**
|
||||
* UID argument to check for nodes that user posted or commented on.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*
|
||||
* @ViewsArgument("tracker_user_uid")
|
||||
*/
|
||||
class UserUid extends CommentUserUid {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query($group_by = FALSE) {
|
||||
// Because this handler thinks it's an argument for a field on the {node}
|
||||
// table, we need to make sure {tracker_user} is JOINed and use its alias
|
||||
// for the WHERE clause.
|
||||
$tracker_user_alias = $this->query->ensureTable('tracker_user');
|
||||
$this->query->addWhere(0, "$tracker_user_alias.uid", $this->argument);
|
||||
}
|
||||
|
||||
}
|
28
web/core/modules/tracker/src/Plugin/views/filter/UserUid.php
Normal file
28
web/core/modules/tracker/src/Plugin/views/filter/UserUid.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Plugin\views\filter;
|
||||
|
||||
use Drupal\user\Plugin\views\filter\Name;
|
||||
|
||||
/**
|
||||
* UID filter to check for nodes that a user posted or commented on.
|
||||
*
|
||||
* @ingroup views_filter_handlers
|
||||
*
|
||||
* @ViewsFilter("tracker_user_uid")
|
||||
*/
|
||||
class UserUid extends Name {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
// Because this handler thinks it's an argument for a field on the {node}
|
||||
// table, we need to make sure {tracker_user} is JOINed and use its alias
|
||||
// for the WHERE clause.
|
||||
$tracker_user_alias = $this->query->ensureTable('tracker_user');
|
||||
// Cast scalars to array so we can consistently use an IN condition.
|
||||
$this->query->addWhere(0, "$tracker_user_alias.uid", (array) $this->value, 'IN');
|
||||
}
|
||||
|
||||
}
|
75
web/core/modules/tracker/src/Tests/TrackerNodeAccessTest.php
Normal file
75
web/core/modules/tracker/src/Tests/TrackerNodeAccessTest.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Tests;
|
||||
|
||||
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests for private node access on /tracker.
|
||||
*
|
||||
* @group tracker
|
||||
*/
|
||||
class TrackerNodeAccessTest extends WebTestBase {
|
||||
|
||||
use CommentTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'comment', 'tracker', 'node_access_test');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
node_access_rebuild();
|
||||
$this->drupalCreateContentType(array('type' => 'page'));
|
||||
node_access_test_add_field(NodeType::load('page'));
|
||||
$this->addDefaultCommentField('node', 'page', 'comment', CommentItemInterface::OPEN);
|
||||
\Drupal::state()->set('node_access_test.private', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure private node on /tracker is only visible to users with permission.
|
||||
*/
|
||||
function testTrackerNodeAccess() {
|
||||
// Create user with node test view permission.
|
||||
$access_user = $this->drupalCreateUser(array('node test view', 'access user profiles'));
|
||||
|
||||
// Create user without node test view permission.
|
||||
$no_access_user = $this->drupalCreateUser(array('access user profiles'));
|
||||
|
||||
$this->drupalLogin($access_user);
|
||||
|
||||
// Create some nodes.
|
||||
$private_node = $this->drupalCreateNode(array(
|
||||
'title' => t('Private node test'),
|
||||
'private' => TRUE,
|
||||
));
|
||||
$public_node = $this->drupalCreateNode(array(
|
||||
'title' => t('Public node test'),
|
||||
'private' => FALSE,
|
||||
));
|
||||
|
||||
// User with access should see both nodes created.
|
||||
$this->drupalGet('activity');
|
||||
$this->assertText($private_node->getTitle(), 'Private node is visible to user with private access.');
|
||||
$this->assertText($public_node->getTitle(), 'Public node is visible to user with private access.');
|
||||
$this->drupalGet('user/' . $access_user->id() . '/activity');
|
||||
$this->assertText($private_node->getTitle(), 'Private node is visible to user with private access.');
|
||||
$this->assertText($public_node->getTitle(), 'Public node is visible to user with private access.');
|
||||
|
||||
// User without access should not see private node.
|
||||
$this->drupalLogin($no_access_user);
|
||||
$this->drupalGet('activity');
|
||||
$this->assertNoText($private_node->getTitle(), 'Private node is not visible to user without private access.');
|
||||
$this->assertText($public_node->getTitle(), 'Public node is visible to user without private access.');
|
||||
$this->drupalGet('user/' . $access_user->id() . '/activity');
|
||||
$this->assertNoText($private_node->getTitle(), 'Private node is not visible to user without private access.');
|
||||
$this->assertText($public_node->getTitle(), 'Public node is visible to user without private access.');
|
||||
}
|
||||
|
||||
}
|
448
web/core/modules/tracker/src/Tests/TrackerTest.php
Normal file
448
web/core/modules/tracker/src/Tests/TrackerTest.php
Normal file
|
@ -0,0 +1,448 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Tests;
|
||||
|
||||
use Drupal\comment\CommentInterface;
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* Create and delete nodes and check for their display in the tracker listings.
|
||||
*
|
||||
* @group tracker
|
||||
*/
|
||||
class TrackerTest extends WebTestBase {
|
||||
|
||||
use CommentTestTrait;
|
||||
use AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['block', 'comment', 'tracker', 'history', 'node_test'];
|
||||
|
||||
/**
|
||||
* The main user for testing.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* A second user that will 'create' comments and nodes.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $otherUser;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
|
||||
|
||||
$permissions = array('access comments', 'create page content', 'post comments', 'skip comment approval');
|
||||
$this->user = $this->drupalCreateUser($permissions);
|
||||
$this->otherUser = $this->drupalCreateUser($permissions);
|
||||
$this->addDefaultCommentField('node', 'page');
|
||||
user_role_grant_permissions(AccountInterface::ANONYMOUS_ROLE, array(
|
||||
'access content',
|
||||
'access user profiles',
|
||||
));
|
||||
$this->drupalPlaceBlock('local_tasks_block', ['id' => 'page_tabs_block']);
|
||||
$this->drupalPlaceBlock('local_actions_block', ['id' => 'page_actions_block']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for the presence of nodes on the global tracker listing.
|
||||
*/
|
||||
function testTrackerAll() {
|
||||
$this->drupalLogin($this->user);
|
||||
|
||||
$unpublished = $this->drupalCreateNode(array(
|
||||
'title' => $this->randomMachineName(8),
|
||||
'status' => 0,
|
||||
));
|
||||
$published = $this->drupalCreateNode(array(
|
||||
'title' => $this->randomMachineName(8),
|
||||
'status' => 1,
|
||||
));
|
||||
|
||||
$this->drupalGet('activity');
|
||||
$this->assertNoText($unpublished->label(), 'Unpublished node does not show up in the tracker listing.');
|
||||
$this->assertText($published->label(), 'Published node shows up in the tracker listing.');
|
||||
$this->assertLink(t('My recent content'), 0, 'User tab shows up on the global tracker page.');
|
||||
|
||||
// Assert cache contexts, specifically the pager and node access contexts.
|
||||
$this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user.node_grants:view', 'user']);
|
||||
// Assert cache tags for the action/tabs blocks, visible node, and node list
|
||||
// cache tag.
|
||||
$expected_tags = Cache::mergeTags($published->getCacheTags(), $published->getOwner()->getCacheTags());
|
||||
// Because the 'user.permissions' cache context is being optimized away.
|
||||
$role_tags = [];
|
||||
foreach ($this->user->getRoles() as $rid) {
|
||||
$role_tags[] = "config:user.role.$rid";
|
||||
}
|
||||
$expected_tags = Cache::mergeTags($expected_tags, $role_tags);
|
||||
$block_tags = [
|
||||
'block_view',
|
||||
'config:block.block.page_actions_block',
|
||||
'config:block.block.page_tabs_block',
|
||||
'config:block_list',
|
||||
];
|
||||
$expected_tags = Cache::mergeTags($expected_tags, $block_tags);
|
||||
$additional_tags = [
|
||||
'node_list',
|
||||
'rendered',
|
||||
];
|
||||
$expected_tags = Cache::mergeTags($expected_tags, $additional_tags);
|
||||
$this->assertCacheTags($expected_tags);
|
||||
|
||||
// Delete a node and ensure it no longer appears on the tracker.
|
||||
$published->delete();
|
||||
$this->drupalGet('activity');
|
||||
$this->assertNoText($published->label(), 'Deleted node does not show up in the tracker listing.');
|
||||
|
||||
// Test proper display of time on activity page when comments are disabled.
|
||||
// Disable comments.
|
||||
FieldStorageConfig::loadByName('node', 'comment')->delete();
|
||||
$node = $this->drupalCreateNode([
|
||||
// This title is required to trigger the custom changed time set in the
|
||||
// node_test module. This is needed in order to ensure a sufficiently
|
||||
// large 'time ago' interval that isn't numbered in seconds.
|
||||
'title' => 'testing_node_presave',
|
||||
'status' => 1,
|
||||
]);
|
||||
|
||||
$this->drupalGet('activity');
|
||||
$this->assertText($node->label(), 'Published node shows up in the tracker listing.');
|
||||
$this->assertText(\Drupal::service('date.formatter')->formatTimeDiffSince($node->getChangedTime()), 'The changed time was displayed on the tracker listing.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for the presence of nodes on a user's tracker listing.
|
||||
*/
|
||||
function testTrackerUser() {
|
||||
$this->drupalLogin($this->user);
|
||||
|
||||
$unpublished = $this->drupalCreateNode(array(
|
||||
'title' => $this->randomMachineName(8),
|
||||
'uid' => $this->user->id(),
|
||||
'status' => 0,
|
||||
));
|
||||
$my_published = $this->drupalCreateNode(array(
|
||||
'title' => $this->randomMachineName(8),
|
||||
'uid' => $this->user->id(),
|
||||
'status' => 1,
|
||||
));
|
||||
$other_published_no_comment = $this->drupalCreateNode(array(
|
||||
'title' => $this->randomMachineName(8),
|
||||
'uid' => $this->otherUser->id(),
|
||||
'status' => 1,
|
||||
));
|
||||
$other_published_my_comment = $this->drupalCreateNode(array(
|
||||
'title' => $this->randomMachineName(8),
|
||||
'uid' => $this->otherUser->id(),
|
||||
'status' => 1,
|
||||
));
|
||||
$comment = array(
|
||||
'subject[0][value]' => $this->randomMachineName(),
|
||||
'comment_body[0][value]' => $this->randomMachineName(20),
|
||||
);
|
||||
$this->drupalPostForm('comment/reply/node/' . $other_published_my_comment->id() . '/comment', $comment, t('Save'));
|
||||
|
||||
$this->drupalGet('user/' . $this->user->id() . '/activity');
|
||||
$this->assertNoText($unpublished->label(), "Unpublished nodes do not show up in the user's tracker listing.");
|
||||
$this->assertText($my_published->label(), "Published nodes show up in the user's tracker listing.");
|
||||
$this->assertNoText($other_published_no_comment->label(), "Another user's nodes do not show up in the user's tracker listing.");
|
||||
$this->assertText($other_published_my_comment->label(), "Nodes that the user has commented on appear in the user's tracker listing.");
|
||||
|
||||
// Assert cache contexts.
|
||||
$this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user', 'user.node_grants:view']);
|
||||
// Assert cache tags for the visible nodes (including owners) and node list
|
||||
// cache tag.
|
||||
$expected_tags = Cache::mergeTags($my_published->getCacheTags(), $my_published->getOwner()->getCacheTags());
|
||||
$expected_tags = Cache::mergeTags($expected_tags, $other_published_my_comment->getCacheTags());
|
||||
$expected_tags = Cache::mergeTags($expected_tags, $other_published_my_comment->getOwner()->getCacheTags());
|
||||
// Because the 'user.permissions' cache context is being optimized away.
|
||||
$role_tags = [];
|
||||
foreach ($this->user->getRoles() as $rid) {
|
||||
$role_tags[] = "config:user.role.$rid";
|
||||
}
|
||||
$expected_tags = Cache::mergeTags($expected_tags, $role_tags);
|
||||
$block_tags = [
|
||||
'block_view',
|
||||
'config:block.block.page_actions_block',
|
||||
'config:block.block.page_tabs_block',
|
||||
'config:block_list',
|
||||
];
|
||||
$expected_tags = Cache::mergeTags($expected_tags, $block_tags);
|
||||
$additional_tags = [
|
||||
'node_list',
|
||||
'rendered',
|
||||
];
|
||||
$expected_tags = Cache::mergeTags($expected_tags, $additional_tags);
|
||||
|
||||
$this->assertCacheTags($expected_tags);
|
||||
$this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user', 'user.node_grants:view']);
|
||||
|
||||
$this->assertLink($my_published->label());
|
||||
$this->assertNoLink($unpublished->label());
|
||||
// Verify that title and tab title have been set correctly.
|
||||
$this->assertText('Activity', 'The user activity tab has the name "Activity".');
|
||||
$this->assertTitle(t('@name | @site', array('@name' => $this->user->getUsername(), '@site' => $this->config('system.site')->get('name'))), 'The user tracker page has the correct page title.');
|
||||
|
||||
// Verify that unpublished comments are removed from the tracker.
|
||||
$admin_user = $this->drupalCreateUser(array('post comments', 'administer comments', 'access user profiles'));
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->drupalPostForm('comment/1/edit', array('status' => CommentInterface::NOT_PUBLISHED), t('Save'));
|
||||
$this->drupalGet('user/' . $this->user->id() . '/activity');
|
||||
$this->assertNoText($other_published_my_comment->label(), 'Unpublished comments are not counted on the tracker listing.');
|
||||
|
||||
// Test escaping of title on user's tracker tab.
|
||||
\Drupal::service('module_installer')->install(['user_hooks_test']);
|
||||
Cache::invalidateTags(['rendered']);
|
||||
\Drupal::state()->set('user_hooks_test_user_format_name_alter', TRUE);
|
||||
$this->drupalGet('user/' . $this->user->id() . '/activity');
|
||||
$this->assertEscaped('<em>' . $this->user->id() . '</em>');
|
||||
|
||||
\Drupal::state()->set('user_hooks_test_user_format_name_alter_safe', TRUE);
|
||||
Cache::invalidateTags(['rendered']);
|
||||
$this->drupalGet('user/' . $this->user->id() . '/activity');
|
||||
$this->assertNoEscaped('<em>' . $this->user->id() . '</em>');
|
||||
$this->assertRaw('<em>' . $this->user->id() . '</em>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the metadata for the "new"/"updated" indicators.
|
||||
*/
|
||||
function testTrackerHistoryMetadata() {
|
||||
$this->drupalLogin($this->user);
|
||||
|
||||
// Create a page node.
|
||||
$edit = array(
|
||||
'title' => $this->randomMachineName(8),
|
||||
);
|
||||
$node = $this->drupalCreateNode($edit);
|
||||
|
||||
// Verify that the history metadata is present.
|
||||
$this->drupalGet('activity');
|
||||
$this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->getChangedTime());
|
||||
$this->drupalGet('activity/' . $this->user->id());
|
||||
$this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->getChangedTime());
|
||||
$this->drupalGet('user/' . $this->user->id() . '/activity');
|
||||
$this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->getChangedTime());
|
||||
|
||||
// Add a comment to the page, make sure it is created after the node by
|
||||
// sleeping for one second, to ensure the last comment timestamp is
|
||||
// different from before.
|
||||
$comment = array(
|
||||
'subject[0][value]' => $this->randomMachineName(),
|
||||
'comment_body[0][value]' => $this->randomMachineName(20),
|
||||
);
|
||||
sleep(1);
|
||||
$this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $comment, t('Save'));
|
||||
// Reload the node so that comment.module's hook_node_load()
|
||||
// implementation can set $node->last_comment_timestamp for the freshly
|
||||
// posted comment.
|
||||
$node = Node::load($node->id());
|
||||
|
||||
// Verify that the history metadata is updated.
|
||||
$this->drupalGet('activity');
|
||||
$this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp);
|
||||
$this->drupalGet('activity/' . $this->user->id());
|
||||
$this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp);
|
||||
$this->drupalGet('user/' . $this->user->id() . '/activity');
|
||||
$this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp);
|
||||
|
||||
// Log out, now verify that the metadata is still there, but the library is
|
||||
// not.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('activity');
|
||||
$this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp, FALSE);
|
||||
$this->drupalGet('user/' . $this->user->id() . '/activity');
|
||||
$this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for ordering on a users tracker listing when comments are posted.
|
||||
*/
|
||||
function testTrackerOrderingNewComments() {
|
||||
$this->drupalLogin($this->user);
|
||||
|
||||
$node_one = $this->drupalCreateNode(array(
|
||||
'title' => $this->randomMachineName(8),
|
||||
));
|
||||
|
||||
$node_two = $this->drupalCreateNode(array(
|
||||
'title' => $this->randomMachineName(8),
|
||||
));
|
||||
|
||||
// Now get otherUser to track these pieces of content.
|
||||
$this->drupalLogin($this->otherUser);
|
||||
|
||||
// Add a comment to the first page.
|
||||
$comment = array(
|
||||
'subject[0][value]' => $this->randomMachineName(),
|
||||
'comment_body[0][value]' => $this->randomMachineName(20),
|
||||
);
|
||||
$this->drupalPostForm('comment/reply/node/' . $node_one->id() . '/comment', $comment, t('Save'));
|
||||
|
||||
// If the comment is posted in the same second as the last one then Drupal
|
||||
// can't tell the difference, so we wait one second here.
|
||||
sleep(1);
|
||||
|
||||
// Add a comment to the second page.
|
||||
$comment = array(
|
||||
'subject[0][value]' => $this->randomMachineName(),
|
||||
'comment_body[0][value]' => $this->randomMachineName(20),
|
||||
);
|
||||
$this->drupalPostForm('comment/reply/node/' . $node_two->id() . '/comment', $comment, t('Save'));
|
||||
|
||||
// We should at this point have in our tracker for otherUser:
|
||||
// 1. node_two
|
||||
// 2. node_one
|
||||
// Because that's the reverse order of the posted comments.
|
||||
|
||||
// Now we're going to post a comment to node_one which should jump it to the
|
||||
// top of the list.
|
||||
|
||||
$this->drupalLogin($this->user);
|
||||
// If the comment is posted in the same second as the last one then Drupal
|
||||
// can't tell the difference, so we wait one second here.
|
||||
sleep(1);
|
||||
|
||||
// Add a comment to the second page.
|
||||
$comment = array(
|
||||
'subject[0][value]' => $this->randomMachineName(),
|
||||
'comment_body[0][value]' => $this->randomMachineName(20),
|
||||
);
|
||||
$this->drupalPostForm('comment/reply/node/' . $node_one->id() . '/comment', $comment, t('Save'));
|
||||
|
||||
// Switch back to the otherUser and assert that the order has swapped.
|
||||
$this->drupalLogin($this->otherUser);
|
||||
$this->drupalGet('user/' . $this->otherUser->id() . '/activity');
|
||||
// This is a cheeky way of asserting that the nodes are in the right order
|
||||
// on the tracker page.
|
||||
// It's almost certainly too brittle.
|
||||
$pattern = '/' . preg_quote($node_one->getTitle()) . '.+' . preg_quote($node_two->getTitle()) . '/s';
|
||||
$this->verbose($pattern);
|
||||
$this->assertPattern($pattern, 'Most recently commented on node appears at the top of tracker');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that existing nodes are indexed by cron.
|
||||
*/
|
||||
function testTrackerCronIndexing() {
|
||||
$this->drupalLogin($this->user);
|
||||
|
||||
// Create 3 nodes.
|
||||
$edits = array();
|
||||
$nodes = array();
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
$edits[$i] = array(
|
||||
'title' => $this->randomMachineName(),
|
||||
);
|
||||
$nodes[$i] = $this->drupalCreateNode($edits[$i]);
|
||||
}
|
||||
|
||||
// Add a comment to the last node as other user.
|
||||
$this->drupalLogin($this->otherUser);
|
||||
$comment = array(
|
||||
'subject[0][value]' => $this->randomMachineName(),
|
||||
'comment_body[0][value]' => $this->randomMachineName(20),
|
||||
);
|
||||
$this->drupalPostForm('comment/reply/node/' . $nodes[3]->id() . '/comment', $comment, t('Save'));
|
||||
|
||||
// Start indexing backwards from node 3.
|
||||
\Drupal::state()->set('tracker.index_nid', 3);
|
||||
|
||||
// Clear the current tracker tables and rebuild them.
|
||||
db_delete('tracker_node')
|
||||
->execute();
|
||||
db_delete('tracker_user')
|
||||
->execute();
|
||||
tracker_cron();
|
||||
|
||||
$this->drupalLogin($this->user);
|
||||
|
||||
// Fetch the user's tracker.
|
||||
$this->drupalGet('activity/' . $this->user->id());
|
||||
|
||||
// Assert that all node titles are displayed.
|
||||
foreach ($nodes as $i => $node) {
|
||||
$this->assertText($node->label(), format_string('Node @i is displayed on the tracker listing pages.', array('@i' => $i)));
|
||||
}
|
||||
|
||||
// Fetch the site-wide tracker.
|
||||
$this->drupalGet('activity');
|
||||
|
||||
// Assert that all node titles are displayed.
|
||||
foreach ($nodes as $i => $node) {
|
||||
$this->assertText($node->label(), format_string('Node @i is displayed on the tracker listing pages.', array('@i' => $i)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that publish/unpublish works at admin/content/node.
|
||||
*/
|
||||
function testTrackerAdminUnpublish() {
|
||||
\Drupal::service('module_installer')->install(array('views'));
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
$admin_user = $this->drupalCreateUser(array('access content overview', 'administer nodes', 'bypass node access'));
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
$node = $this->drupalCreateNode(array(
|
||||
'title' => $this->randomMachineName(),
|
||||
));
|
||||
|
||||
// Assert that the node is displayed.
|
||||
$this->drupalGet('activity');
|
||||
$this->assertText($node->label(), 'A node is displayed on the tracker listing pages.');
|
||||
|
||||
// Unpublish the node and ensure that it's no longer displayed.
|
||||
$edit = array(
|
||||
'action' => 'node_unpublish_action',
|
||||
'node_bulk_form[0]' => $node->id(),
|
||||
);
|
||||
$this->drupalPostForm('admin/content', $edit, t('Apply to selected items'));
|
||||
|
||||
$this->drupalGet('activity');
|
||||
$this->assertText(t('No content available.'), 'A node is displayed on the tracker listing pages.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if the appropriate history metadata exists.
|
||||
*
|
||||
* Verify the data-history-node-id, data-history-node-timestamp and
|
||||
* data-history-node-last-comment-timestamp attributes, which are used by the
|
||||
* drupal.tracker-history library to add the appropriate "new" and "updated"
|
||||
* indicators, as well as the "x new" replies link to the tracker.
|
||||
* We do this in JavaScript to prevent breaking the render cache.
|
||||
*
|
||||
* @param int $node_id
|
||||
* A node ID, that must exist as a data-history-node-id attribute
|
||||
* @param int $node_timestamp
|
||||
* A node timestamp, that must exist as a data-history-node-timestamp
|
||||
* attribute.
|
||||
* @param int $node_last_comment_timestamp
|
||||
* A node's last comment timestamp, that must exist as a
|
||||
* data-history-node-last-comment-timestamp attribute.
|
||||
* @param bool $library_is_present
|
||||
* Whether the drupal.tracker-history library should be present or not.
|
||||
*/
|
||||
function assertHistoryMetadata($node_id, $node_timestamp, $node_last_comment_timestamp, $library_is_present = TRUE) {
|
||||
$settings = $this->getDrupalSettings();
|
||||
$this->assertIdentical($library_is_present, isset($settings['ajaxPageState']) && in_array('tracker/history', explode(',', $settings['ajaxPageState']['libraries'])), 'drupal.tracker-history library is present.');
|
||||
$this->assertIdentical(1, count($this->xpath('//table/tbody/tr/td[@data-history-node-id="' . $node_id . '" and @data-history-node-timestamp="' . $node_timestamp . '"]')), 'Tracker table cell contains the data-history-node-id and data-history-node-timestamp attributes for the node.');
|
||||
$this->assertIdentical(1, count($this->xpath('//table/tbody/tr/td[@data-history-node-last-comment-timestamp="' . $node_last_comment_timestamp . '"]')), 'Tracker table cell contains the data-history-node-last-comment-timestamp attribute for the node.');
|
||||
}
|
||||
|
||||
}
|
69
web/core/modules/tracker/src/Tests/Views/TrackerTestBase.php
Normal file
69
web/core/modules/tracker/src/Tests/Views/TrackerTestBase.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Tests\Views;
|
||||
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\views\Tests\ViewTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\comment\Entity\Comment;
|
||||
|
||||
/**
|
||||
* Base class for all tracker tests.
|
||||
*/
|
||||
abstract class TrackerTestBase extends ViewTestBase {
|
||||
|
||||
use CommentTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('comment', 'tracker', 'tracker_test_views');
|
||||
|
||||
/**
|
||||
* The node used for testing.
|
||||
*
|
||||
* @var \Drupal\node\NodeInterface
|
||||
*/
|
||||
protected $node;
|
||||
|
||||
/**
|
||||
* The comment used for testing.
|
||||
*
|
||||
* @var \Drupal\comment\CommentInterface
|
||||
*/
|
||||
protected $comment;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
ViewTestData::createTestViews(get_class($this), array('tracker_test_views'));
|
||||
|
||||
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
|
||||
// Add a comment field.
|
||||
$this->addDefaultCommentField('node', 'page');
|
||||
|
||||
$permissions = array('access comments', 'create page content', 'post comments', 'skip comment approval');
|
||||
$account = $this->drupalCreateUser($permissions);
|
||||
|
||||
$this->drupalLogin($account);
|
||||
|
||||
$this->node = $this->drupalCreateNode(array(
|
||||
'title' => $this->randomMachineName(8),
|
||||
'uid' => $account->id(),
|
||||
'status' => 1,
|
||||
));
|
||||
|
||||
$this->comment = Comment::create(array(
|
||||
'entity_id' => $this->node->id(),
|
||||
'entity_type' => 'node',
|
||||
'field_name' => 'comment',
|
||||
'subject' => $this->randomMachineName(),
|
||||
'comment_body[' . LanguageInterface::LANGCODE_NOT_SPECIFIED . '][0][value]' => $this->randomMachineName(20),
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\tracker\Tests\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the tracker user uid handlers.
|
||||
*
|
||||
* @group tracker
|
||||
*/
|
||||
class TrackerUserUidTest extends TrackerTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = array('test_tracker_user_uid');
|
||||
|
||||
/**
|
||||
* Tests the user uid filter and argument.
|
||||
*/
|
||||
public function testUserUid() {
|
||||
$map = array(
|
||||
'nid' => 'nid',
|
||||
'title' => 'title',
|
||||
);
|
||||
|
||||
$expected = array(
|
||||
array(
|
||||
'nid' => $this->node->id(),
|
||||
'title' => $this->node->label(),
|
||||
)
|
||||
);
|
||||
|
||||
$view = Views::getView('test_tracker_user_uid');
|
||||
$this->executeView($view);
|
||||
|
||||
// We should have no results as the filter is set for uid 0.
|
||||
$this->assertIdenticalResultSet($view, array(), $map);
|
||||
$view->destroy();
|
||||
|
||||
// Change the filter value to our user.
|
||||
$view->initHandlers();
|
||||
$view->filter['uid_touch_tracker']->value = $this->node->getOwnerId();
|
||||
$this->executeView($view);
|
||||
|
||||
// We should have one result as the filter is set for the created user.
|
||||
$this->assertIdenticalResultSet($view, $expected, $map);
|
||||
$view->destroy();
|
||||
|
||||
// Remove the filter now, so only the argument will affect the query.
|
||||
$view->removeHandler('default', 'filter', 'uid_touch_tracker');
|
||||
|
||||
// Test the incorrect argument UID.
|
||||
$view->initHandlers();
|
||||
$this->executeView($view, array(rand()));
|
||||
$this->assertIdenticalResultSet($view, array(), $map);
|
||||
$view->destroy();
|
||||
|
||||
// Test the correct argument UID.
|
||||
$view->initHandlers();
|
||||
$this->executeView($view, array($this->node->getOwnerId()));
|
||||
$this->assertIdenticalResultSet($view, $expected, $map);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
- tracker
|
||||
- user
|
||||
id: test_tracker_user_uid
|
||||
label: 'tracker test'
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: null
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
cache:
|
||||
type: tag
|
||||
query:
|
||||
type: views_query
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: full
|
||||
style:
|
||||
type: table
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
override: true
|
||||
sticky: false
|
||||
summary: ''
|
||||
columns:
|
||||
title: title
|
||||
info:
|
||||
title:
|
||||
sortable: true
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
default: '-1'
|
||||
empty_table: false
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
field: title
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Title
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
plugin_id: field
|
||||
entity_type: node
|
||||
entity_field: title
|
||||
filters:
|
||||
uid_touch_tracker:
|
||||
id: uid_touch_tracker
|
||||
table: node_field_data
|
||||
field: uid_touch_tracker
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: in
|
||||
value:
|
||||
- '0'
|
||||
group: 1
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: 'User posted or commented'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: uid_touch_tracker_op
|
||||
identifier: uid_touch_tracker
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
reduce: false
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
plugin_id: tracker_user_uid
|
||||
entity_type: node
|
||||
arguments:
|
||||
uid_touch_tracker:
|
||||
id: uid_touch_tracker
|
||||
table: node_field_data
|
||||
field: uid_touch_tracker
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: ignore
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
default_argument_skip_url: false
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: false
|
||||
validate:
|
||||
type: none
|
||||
fail: 'not found'
|
||||
validate_options: { }
|
||||
plugin_id: tracker_user_uid
|
||||
entity_type: node
|
|
@ -0,0 +1,9 @@
|
|||
name: 'Tracker test views'
|
||||
type: module
|
||||
description: 'Provides default views for views tracker tests.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- tracker
|
||||
- views
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\tracker\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
/**
|
||||
* Tests migration of tracker_node.
|
||||
*
|
||||
* @group tracker
|
||||
*/
|
||||
class MigrateTrackerNodeTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'node',
|
||||
'text',
|
||||
'tracker',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('node');
|
||||
$this->installConfig(static::$modules);
|
||||
$this->installSchema('node', ['node_access']);
|
||||
$this->installSchema('tracker', ['tracker_node', 'tracker_user']);
|
||||
|
||||
$this->executeMigrations([
|
||||
'd7_user_role',
|
||||
'd7_user',
|
||||
'd7_node_type',
|
||||
'd7_node',
|
||||
'd7_tracker_node',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of tracker node table.
|
||||
*/
|
||||
public function testMigrateTrackerNode() {
|
||||
$connection = Database::getConnection('default', 'migrate');
|
||||
$num_rows = $connection
|
||||
->select('tracker_node', 'tn')
|
||||
->fields('tn', ['nid', 'published', 'changed'])
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertIdentical('1', $num_rows);
|
||||
|
||||
$tracker_nodes = $connection
|
||||
->select('tracker_node', 'tn')
|
||||
->fields('tn', ['nid', 'published', 'changed'])
|
||||
->execute();
|
||||
$row = $tracker_nodes->fetchAssoc();
|
||||
$this->assertIdentical('1', $row['nid']);
|
||||
$this->assertIdentical('1', $row['published']);
|
||||
$this->assertIdentical('1421727536', $row['changed']);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\tracker\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests migration of Tracker settings to configuration.
|
||||
*
|
||||
* @group tracker
|
||||
*/
|
||||
class MigrateTrackerSettingsTest extends MigrateDrupal7TestBase {
|
||||
|
||||
public static $modules = ['tracker'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installConfig(['tracker']);
|
||||
$this->executeMigration('d7_tracker_settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of tracker's variables to configuration.
|
||||
*/
|
||||
public function testMigration() {
|
||||
$this->assertIdentical(999, \Drupal::config('tracker.settings')->get('cron_index_limit'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\tracker\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
/**
|
||||
* Tests migration of tracker_user.
|
||||
*
|
||||
* @group tracker
|
||||
*/
|
||||
class MigrateTrackerUserTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'node',
|
||||
'text',
|
||||
'tracker',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('node');
|
||||
$this->installConfig(static::$modules);
|
||||
$this->installSchema('node', ['node_access']);
|
||||
$this->installSchema('tracker', ['tracker_node', 'tracker_user']);
|
||||
|
||||
$this->executeMigrations([
|
||||
'd7_user_role',
|
||||
'd7_user',
|
||||
'd7_node_type',
|
||||
'd7_node',
|
||||
'd7_tracker_node',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration of tracker user table.
|
||||
*/
|
||||
public function testMigrateTrackerUser() {
|
||||
$connection = Database::getConnection('default', 'migrate');
|
||||
$num_rows = $connection
|
||||
->select('tracker_user', 'tn')
|
||||
->fields('tu', ['nid', 'uid', 'published', 'changed'])
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertIdentical('1', $num_rows);
|
||||
|
||||
$tracker_nodes = $connection
|
||||
->select('tracker_user', 'tu')
|
||||
->fields('tu', ['nid', 'uid', 'published', 'changed'])
|
||||
->execute();
|
||||
$row = $tracker_nodes->fetchAssoc();
|
||||
$this->assertIdentical('1', $row['nid']);
|
||||
$this->assertIdentical('2', $row['uid']);
|
||||
$this->assertIdentical('1', $row['published']);
|
||||
$this->assertIdentical('1421727536', $row['changed']);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\tracker\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests D7 tracker node source plugin.
|
||||
*
|
||||
* @covers Drupal\tracker\Plugin\migrate\source\d7\TrackerNode
|
||||
*
|
||||
* @group tracker
|
||||
*/
|
||||
class TrackerNodeTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['tracker', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['database']['tracker_node'] = [
|
||||
[
|
||||
'nid' => '2',
|
||||
'published' => '1',
|
||||
'changed' => '1421727536',
|
||||
]
|
||||
];
|
||||
|
||||
// The expected results are identical to the source data.
|
||||
$tests[0]['expected_results'] = $tests[0]['database']['tracker_node'];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\tracker\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests D7 tracker user source plugin.
|
||||
*
|
||||
* @covers Drupal\tracker\Plugin\migrate\source\d7\TrackerUser
|
||||
*
|
||||
* @group tracker
|
||||
*/
|
||||
class TrackerUserTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['tracker', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['database']['tracker_user'] = [
|
||||
[
|
||||
'nid' => '1',
|
||||
'uid' => '2',
|
||||
'published' => '1',
|
||||
'changed' => '1421727536',
|
||||
]
|
||||
];
|
||||
|
||||
// The expected results are identical to the source data.
|
||||
$tests[0]['expected_results'] = $tests[0]['database']['tracker_user'];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
9
web/core/modules/tracker/tracker.info.yml
Normal file
9
web/core/modules/tracker/tracker.info.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
name: Activity Tracker
|
||||
type: module
|
||||
description: 'Enables tracking of recent content for users.'
|
||||
dependencies:
|
||||
- node
|
||||
- comment
|
||||
package: Core
|
||||
version: VERSION
|
||||
core: 8.x
|
118
web/core/modules/tracker/tracker.install
Normal file
118
web/core/modules/tracker/tracker.install
Normal file
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update, and uninstall functions for tracker.module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function tracker_uninstall() {
|
||||
\Drupal::state()->delete('tracker.index_nid');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function tracker_install() {
|
||||
$max_nid = db_query('SELECT MAX(nid) FROM {node}')->fetchField();
|
||||
if ($max_nid != 0) {
|
||||
\Drupal::state()->set('tracker.index_nid', $max_nid);
|
||||
// To avoid timing out while attempting to do a complete indexing, we
|
||||
// simply call our cron job to remove stale records and begin the process.
|
||||
tracker_cron();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function tracker_schema() {
|
||||
$schema['tracker_node'] = array(
|
||||
'description' => 'Tracks when nodes were last changed or commented on.',
|
||||
'fields' => array(
|
||||
'nid' => array(
|
||||
'description' => 'The {node}.nid this record tracks.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'published' => array(
|
||||
'description' => 'Boolean indicating whether the node is published.',
|
||||
'type' => 'int',
|
||||
'not null' => FALSE,
|
||||
'default' => 0,
|
||||
'size' => 'tiny',
|
||||
),
|
||||
'changed' => array(
|
||||
'description' => 'The Unix timestamp when the node was most recently saved or commented on.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'tracker' => array('published', 'changed'),
|
||||
),
|
||||
'primary key' => array('nid'),
|
||||
'foreign keys' => array(
|
||||
'tracked_node' => array(
|
||||
'table' => 'node',
|
||||
'columns' => array('nid' => 'nid'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['tracker_user'] = array(
|
||||
'description' => 'Tracks when nodes were last changed or commented on, for each user that authored the node or one of its comments.',
|
||||
'fields' => array(
|
||||
'nid' => array(
|
||||
'description' => 'The {node}.nid this record tracks.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'uid' => array(
|
||||
'description' => 'The {users}.uid of the node author or commenter.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'published' => array(
|
||||
'description' => 'Boolean indicating whether the node is published.',
|
||||
'type' => 'int',
|
||||
'not null' => FALSE,
|
||||
'default' => 0,
|
||||
'size' => 'tiny',
|
||||
),
|
||||
'changed' => array(
|
||||
'description' => 'The Unix timestamp when the node was most recently saved or commented on.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'tracker' => array('uid', 'published', 'changed'),
|
||||
),
|
||||
'primary key' => array('nid', 'uid'),
|
||||
'foreign keys' => array(
|
||||
'tracked_node' => array(
|
||||
'table' => 'node',
|
||||
'columns' => array('nid' => 'nid'),
|
||||
),
|
||||
'tracked_user' => array(
|
||||
'table' => 'users',
|
||||
'columns' => array('uid' => 'uid'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $schema;
|
||||
}
|
8
web/core/modules/tracker/tracker.libraries.yml
Normal file
8
web/core/modules/tracker/tracker.libraries.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
history:
|
||||
version: VERSION
|
||||
js:
|
||||
js/tracker-history.js: {}
|
||||
dependencies:
|
||||
- core/jquery
|
||||
- core/drupal
|
||||
- history/api
|
3
web/core/modules/tracker/tracker.links.menu.yml
Normal file
3
web/core/modules/tracker/tracker.links.menu.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
tracker.page:
|
||||
title: 'Recent content'
|
||||
route_name: tracker.page
|
15
web/core/modules/tracker/tracker.links.task.yml
Normal file
15
web/core/modules/tracker/tracker.links.task.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
tracker.page_tab:
|
||||
route_name: tracker.page
|
||||
title: 'Recent content'
|
||||
base_route: tracker.page
|
||||
|
||||
tracker.users_recent_tab:
|
||||
route_name: tracker.users_recent_content
|
||||
title: 'My recent content'
|
||||
base_route: tracker.page
|
||||
class: '\Drupal\tracker\Plugin\Menu\UserTrackerTab'
|
||||
|
||||
tracker.user_tab:
|
||||
route_name: tracker.user_tab
|
||||
base_route: entity.user.canonical
|
||||
title: 'Activity'
|
381
web/core/modules/tracker/tracker.module
Normal file
381
web/core/modules/tracker/tracker.module
Normal file
|
@ -0,0 +1,381 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tracks recent content posted by a user or users.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\comment\CommentInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\NodeInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function tracker_help($route_name, RouteMatchInterface $route_match) {
|
||||
switch ($route_name) {
|
||||
case 'help.page.tracker':
|
||||
$output = '<h3>' . t('About') . '</h3>';
|
||||
$output .= '<p>' . t('The Activity Tracker module displays the most recently added and updated content on your site, and allows you to follow new content created by each user. This module has no configuration options. For more information, see the <a href=":tracker">online documentation for the Activity Tracker module</a>.', array(':tracker' => 'https://www.drupal.org/documentation/modules/tracker')) . '</p>';
|
||||
$output .= '<h3>' . t('Uses') . '</h3>';
|
||||
$output .= '<dl>';
|
||||
$output .= '<dt>' . t('Tracking new and updated site content') . '</dt>';
|
||||
$output .= '<dd>' . t('The <a href=":recent">Recent content</a> page shows new and updated content in reverse chronological order, listing the content type, title, author\'s name, number of comments, and time of last update. Content is considered updated when changes occur in the text, or when new comments are added. The <em>My recent content</em> tab limits the list to the currently logged-in user.', array(':recent' => \Drupal::url('tracker.page'))) . '</dd>';
|
||||
$output .= '<dt>' . t('Tracking user-specific content') . '</dt>';
|
||||
$output .= '<dd>' . t("To follow a specific user's new and updated content, select the <em>Activity</em> tab from the user's profile page.") . '</dd>';
|
||||
$output .= '</dl>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_cron().
|
||||
*
|
||||
* Updates tracking information for any items still to be tracked. The state
|
||||
* 'tracker.index_nid' is set to ((the last node ID that was indexed) - 1) and
|
||||
* used to select the nodes to be processed. If there are no remaining nodes to
|
||||
* process, 'tracker.index_nid' will be 0.
|
||||
* This process does not run regularly on live sites, rather it updates tracking
|
||||
* info once on an existing site just after the tracker module was installed.
|
||||
*/
|
||||
function tracker_cron() {
|
||||
$state = \Drupal::state();
|
||||
$max_nid = $state->get('tracker.index_nid') ?: 0;
|
||||
if ($max_nid > 0) {
|
||||
$last_nid = FALSE;
|
||||
$count = 0;
|
||||
|
||||
$nids = \Drupal::entityQuery('node')
|
||||
->condition('nid', $max_nid, '<=')
|
||||
->sort('nid', 'DESC')
|
||||
->range(0, \Drupal::config('tracker.settings')->get('cron_index_limit'))
|
||||
->execute();
|
||||
|
||||
$nodes = Node::loadMultiple($nids);
|
||||
foreach ($nodes as $nid => $node) {
|
||||
|
||||
// Calculate the changed timestamp for this node.
|
||||
$changed = _tracker_calculate_changed($node);
|
||||
|
||||
// Remove existing data for this node.
|
||||
db_delete('tracker_node')
|
||||
->condition('nid', $nid)
|
||||
->execute();
|
||||
db_delete('tracker_user')
|
||||
->condition('nid', $nid)
|
||||
->execute();
|
||||
|
||||
// Insert the node-level data.
|
||||
db_insert('tracker_node')
|
||||
->fields(array(
|
||||
'nid' => $nid,
|
||||
'published' => $node->isPublished(),
|
||||
'changed' => $changed,
|
||||
))
|
||||
->execute();
|
||||
|
||||
// Insert the user-level data for the node's author.
|
||||
db_insert('tracker_user')
|
||||
->fields(array(
|
||||
'nid' => $nid,
|
||||
'published' => $node->isPublished(),
|
||||
'changed' => $changed,
|
||||
'uid' => $node->getOwnerId(),
|
||||
))
|
||||
->execute();
|
||||
|
||||
// Insert the user-level data for the commenters (except if a commenter
|
||||
// is the node's author).
|
||||
|
||||
// Get unique user IDs via entityQueryAggregate because it's the easiest
|
||||
// database agnostic way. We don't actually care about the comments here
|
||||
// so don't add an aggregate field.
|
||||
$result = \Drupal::entityQueryAggregate('comment')
|
||||
->condition('entity_type', 'node')
|
||||
->condition('entity_id', $node->id())
|
||||
->condition('uid', $node->getOwnerId(), '<>')
|
||||
->condition('status', CommentInterface::PUBLISHED)
|
||||
->groupBy('uid')
|
||||
->execute();
|
||||
if ($result) {
|
||||
$query = db_insert('tracker_user');
|
||||
foreach ($result as $row) {
|
||||
$query->fields(array(
|
||||
'uid' => $row['uid'],
|
||||
'nid' => $nid,
|
||||
'published' => CommentInterface::PUBLISHED,
|
||||
'changed' => $changed,
|
||||
));
|
||||
}
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
// Note that we have indexed at least one node.
|
||||
$last_nid = $nid;
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
||||
if ($last_nid !== FALSE) {
|
||||
// Prepare a starting point for the next run.
|
||||
$state->set('tracker.index_nid', $last_nid - 1);
|
||||
|
||||
\Drupal::logger('tracker')->notice('Indexed %count content items for tracking.', array('%count' => $count));
|
||||
}
|
||||
else {
|
||||
// If all nodes have been indexed, set to zero to skip future cron runs.
|
||||
$state->set('tracker.index_nid', 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Access callback: Determines access permission for a user's own account.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The user account to track.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if a user is accessing tracking info for their own account and
|
||||
* has permission to access the content.
|
||||
*
|
||||
* @see tracker_menu()
|
||||
*/
|
||||
function _tracker_myrecent_access(AccountInterface $account) {
|
||||
// This path is only allowed for authenticated users looking at their own content.
|
||||
return $account->id() && (\Drupal::currentUser()->id() == $account->id()) && $account->hasPermission('access content');
|
||||
}
|
||||
|
||||
/**
|
||||
* Access callback: Determines access permission for an account.
|
||||
*
|
||||
* @param int $account
|
||||
* The user account ID to track.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if a user has permission to access the account for $account and
|
||||
* has permission to access the content.
|
||||
*
|
||||
* @see tracker_menu()
|
||||
*/
|
||||
function _tracker_user_access($account) {
|
||||
return $account->access('view') && $account->hasPermission('access content');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ENTITY_TYPE_insert() for node entities.
|
||||
*
|
||||
* Adds new tracking information for this node since it's new.
|
||||
*/
|
||||
function tracker_node_insert(NodeInterface $node, $arg = 0) {
|
||||
_tracker_add($node->id(), $node->getOwnerId(), $node->getChangedTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ENTITY_TYPE_update() for node entities.
|
||||
*
|
||||
* Adds tracking information for this node since it's been updated.
|
||||
*/
|
||||
function tracker_node_update(NodeInterface $node, $arg = 0) {
|
||||
_tracker_add($node->id(), $node->getOwnerId(), $node->getChangedTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ENTITY_TYPE_predelete() for node entities.
|
||||
*
|
||||
* Deletes tracking information for a node.
|
||||
*/
|
||||
function tracker_node_predelete(EntityInterface $node, $arg = 0) {
|
||||
db_delete('tracker_node')
|
||||
->condition('nid', $node->id())
|
||||
->execute();
|
||||
db_delete('tracker_user')
|
||||
->condition('nid', $node->id())
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ENTITY_TYPE_update() for comment entities.
|
||||
*/
|
||||
function tracker_comment_update(CommentInterface $comment) {
|
||||
if ($comment->getCommentedEntityTypeId() == 'node') {
|
||||
if ($comment->isPublished()) {
|
||||
_tracker_add($comment->getCommentedEntityId(), $comment->getOwnerId(), $comment->getChangedTime());
|
||||
}
|
||||
else {
|
||||
_tracker_remove($comment->getCommentedEntityId(), $comment->getOwnerId(), $comment->getChangedTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ENTITY_TYPE_insert() for comment entities.
|
||||
*/
|
||||
function tracker_comment_insert(CommentInterface $comment) {
|
||||
if ($comment->getCommentedEntityTypeId() == 'node' && $comment->isPublished()) {
|
||||
_tracker_add($comment->getCommentedEntityId(), $comment->getOwnerId(), $comment->getChangedTime());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ENTITY_TYPE_delete() for comment entities.
|
||||
*/
|
||||
function tracker_comment_delete(CommentInterface $comment) {
|
||||
if ($comment->getCommentedEntityTypeId() == 'node') {
|
||||
_tracker_remove($comment->getCommentedEntityId(), $comment->getOwnerId(), $comment->getChangedTime());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates indexing tables when a node is added, updated, or commented on.
|
||||
*
|
||||
* @param int $nid
|
||||
* A node ID.
|
||||
* @param int $uid
|
||||
* The node or comment author.
|
||||
* @param int $changed
|
||||
* The node updated timestamp or comment timestamp.
|
||||
*/
|
||||
function _tracker_add($nid, $uid, $changed) {
|
||||
// @todo This should be actually filtering on the desired language and just
|
||||
// fall back to the default language.
|
||||
$node = db_query('SELECT nid, status, uid, changed FROM {node_field_data} WHERE nid = :nid AND default_langcode = 1 ORDER BY changed DESC, status DESC', array(':nid' => $nid))->fetchObject();
|
||||
|
||||
// Adding a comment can only increase the changed timestamp, so our
|
||||
// calculation here is simple.
|
||||
$changed = max($node->changed, $changed);
|
||||
|
||||
// Update the node-level data.
|
||||
db_merge('tracker_node')
|
||||
->key('nid', $nid)
|
||||
->fields(array(
|
||||
'changed' => $changed,
|
||||
'published' => $node->status,
|
||||
))
|
||||
->execute();
|
||||
|
||||
// Create or update the user-level data, first for the user posting.
|
||||
db_merge('tracker_user')
|
||||
->keys(array(
|
||||
'nid' => $nid,
|
||||
'uid' => $uid,
|
||||
))
|
||||
->fields(array(
|
||||
'changed' => $changed,
|
||||
'published' => $node->status,
|
||||
))
|
||||
->execute();
|
||||
// Update the times for all the other users tracking the post.
|
||||
db_update('tracker_user')
|
||||
->condition('nid', $nid)
|
||||
->fields(array(
|
||||
'changed' => $changed,
|
||||
'published' => $node->status,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks the most recent timestamp between node changed and the last comment.
|
||||
*
|
||||
* @param \Drupal\node\NodeInterface $node
|
||||
* The node entity.
|
||||
*
|
||||
* @return int
|
||||
* The node changed timestamp, or most recent comment timestamp, whichever is
|
||||
* the greatest.
|
||||
*
|
||||
* @todo Check if we should introduce 'language context' here, because the
|
||||
* callers may need different timestamps depending on the users' language?
|
||||
*/
|
||||
function _tracker_calculate_changed($node) {
|
||||
$changed = $node->getChangedTime();
|
||||
$latest_comment = \Drupal::service('comment.statistics')->read(array($node), 'node', FALSE);
|
||||
if ($latest_comment && $latest_comment->last_comment_timestamp > $changed) {
|
||||
$changed = $latest_comment->last_comment_timestamp;
|
||||
}
|
||||
return $changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up indexed data when nodes or comments are removed.
|
||||
*
|
||||
* @param int $nid
|
||||
* The node ID.
|
||||
* @param int $uid
|
||||
* The author of the node or comment.
|
||||
* @param int $changed
|
||||
* The last changed timestamp of the node.
|
||||
*/
|
||||
function _tracker_remove($nid, $uid = NULL, $changed = NULL) {
|
||||
$node = Node::load($nid);
|
||||
|
||||
// The user only keeps their subscription if the node exists.
|
||||
if ($node) {
|
||||
// And they are the author of the node.
|
||||
$keep_subscription = ($node->getOwnerId() == $uid);
|
||||
|
||||
// Or if they have commented on the node.
|
||||
if (!$keep_subscription) {
|
||||
// Check if the user has commented at least once on the given nid.
|
||||
$keep_subscription = \Drupal::entityQuery('comment')
|
||||
->condition('entity_type', 'node')
|
||||
->condition('entity_id', $nid)
|
||||
->condition('uid', $uid)
|
||||
->condition('status', CommentInterface::PUBLISHED)
|
||||
->range(0, 1)
|
||||
->count()
|
||||
->execute();
|
||||
}
|
||||
|
||||
// If we haven't found a reason to keep the user's subscription, delete it.
|
||||
if (!$keep_subscription) {
|
||||
db_delete('tracker_user')
|
||||
->condition('nid', $nid)
|
||||
->condition('uid', $uid)
|
||||
->execute();
|
||||
}
|
||||
|
||||
// Now we need to update the (possibly) changed timestamps for other users
|
||||
// and the node itself.
|
||||
// We only need to do this if the removed item has a timestamp that equals
|
||||
// or exceeds the listed changed timestamp for the node.
|
||||
$tracker_node = db_query('SELECT nid, changed FROM {tracker_node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
|
||||
if ($tracker_node && $changed >= $tracker_node->changed) {
|
||||
// If we're here, the item being removed is *possibly* the item that
|
||||
// established the node's changed timestamp.
|
||||
|
||||
// We just have to recalculate things from scratch.
|
||||
$changed = _tracker_calculate_changed($node);
|
||||
|
||||
// And then we push the out the new changed timestamp to our denormalized
|
||||
// tables.
|
||||
db_update('tracker_node')
|
||||
->fields(array(
|
||||
'changed' => $changed,
|
||||
'published' => $node->isPublished(),
|
||||
))
|
||||
->condition('nid', $nid)
|
||||
->execute();
|
||||
db_update('tracker_node')
|
||||
->fields(array(
|
||||
'changed' => $changed,
|
||||
'published' => $node->isPublished(),
|
||||
))
|
||||
->condition('nid', $nid)
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If the node doesn't exist, remove everything.
|
||||
db_delete('tracker_node')
|
||||
->condition('nid', $nid)
|
||||
->execute();
|
||||
db_delete('tracker_user')
|
||||
->condition('nid', $nid)
|
||||
->execute();
|
||||
}
|
||||
}
|
155
web/core/modules/tracker/tracker.pages.inc
Normal file
155
web/core/modules/tracker/tracker.pages.inc
Normal file
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* User page callbacks for tracker.module.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\node\Entity\Node;
|
||||
|
||||
/**
|
||||
* Page callback: Generates a page of tracked nodes for the site.
|
||||
*
|
||||
* Queries the database for info, adds RDFa info if applicable, and generates
|
||||
* the render array that will be used to render the page.
|
||||
*
|
||||
* @param \Drupal\user\UserInterface $account
|
||||
* (optional) The user account to track.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array.
|
||||
*
|
||||
* @see tracker_menu()
|
||||
*/
|
||||
function tracker_page($account = NULL) {
|
||||
if ($account) {
|
||||
$query = db_select('tracker_user', 't')
|
||||
->extend('Drupal\Core\Database\Query\PagerSelectExtender')
|
||||
->addMetaData('base_table', 'tracker_user')
|
||||
->condition('t.uid', $account->id());
|
||||
}
|
||||
else {
|
||||
$query = db_select('tracker_node', 't', array('target' => 'replica'))
|
||||
->extend('Drupal\Core\Database\Query\PagerSelectExtender')
|
||||
->addMetaData('base_table', 'tracker_node');
|
||||
}
|
||||
|
||||
// This array acts as a placeholder for the data selected later
|
||||
// while keeping the correct order.
|
||||
$tracker_data = $query
|
||||
->addTag('node_access')
|
||||
->fields('t', array('nid', 'changed'))
|
||||
->condition('t.published', 1)
|
||||
->orderBy('t.changed', 'DESC')
|
||||
->limit(25)
|
||||
->execute()
|
||||
->fetchAllAssoc('nid');
|
||||
|
||||
$cache_tags = [];
|
||||
$rows = [];
|
||||
if (!empty($tracker_data)) {
|
||||
// Load nodes into an array with the same order as $tracker_data.
|
||||
$nodes = Node::loadMultiple(array_keys($tracker_data));
|
||||
|
||||
// Enrich the node data.
|
||||
$result = \Drupal::service('comment.statistics')->read($nodes, 'node', FALSE);
|
||||
foreach ($result as $statistics) {
|
||||
// The node ID may not be unique; there can be multiple comment fields.
|
||||
// Make comment_count the total of all comments.
|
||||
$nid = $statistics->entity_id;
|
||||
if (empty($nodes[$nid]->comment_count)
|
||||
|| !is_numeric($nodes[$nid]->comment_count)) {
|
||||
$nodes[$nid]->comment_count = $statistics->comment_count;
|
||||
}
|
||||
else {
|
||||
$nodes[$nid]->comment_count += $statistics->comment_count;
|
||||
}
|
||||
// Make the last comment timestamp reflect the latest comment.
|
||||
if (!isset($nodes[$nid]->last_comment_timestamp)) {
|
||||
$nodes[$nid]->last_comment_timestamp = $statistics->last_comment_timestamp;
|
||||
}
|
||||
else {
|
||||
$nodes[$nid]->last_comment_timestamp = max($nodes[$nid]->last_comment_timestamp, $statistics->last_comment_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
// Display the data.
|
||||
foreach ($nodes as $node) {
|
||||
// Set the last activity time from tracker data. This also takes into
|
||||
// account comment activity, so getChangedTime() is not used.
|
||||
$node->last_activity = $tracker_data[$node->id()]->changed;
|
||||
|
||||
// Determine the number of comments.
|
||||
$comments = 0;
|
||||
if ($node->comment_count) {
|
||||
$comments = $node->comment_count;
|
||||
}
|
||||
|
||||
$row = array(
|
||||
'type' => node_get_type_label($node),
|
||||
'title' => array(
|
||||
'data' => array(
|
||||
'#type' => 'link',
|
||||
'#url' => $node->urlInfo(),
|
||||
'#title' => $node->getTitle(),
|
||||
),
|
||||
'data-history-node-id' => $node->id(),
|
||||
'data-history-node-timestamp' => $node->getChangedTime(),
|
||||
),
|
||||
'author' => array(
|
||||
'data' => array(
|
||||
'#theme' => 'username',
|
||||
'#account' => $node->getOwner(),
|
||||
),
|
||||
),
|
||||
'comments' => array(
|
||||
'class' => array('comments'),
|
||||
'data' => $comments,
|
||||
'data-history-node-last-comment-timestamp' => $node->last_comment_timestamp,
|
||||
),
|
||||
'last updated' => array(
|
||||
'data' => t('@time ago', array(
|
||||
'@time' => \Drupal::service('date.formatter')->formatTimeDiffSince($node->last_activity),
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
$rows[] = $row;
|
||||
|
||||
// Add node and node owner to cache tags.
|
||||
$cache_tags = Cache::mergeTags($cache_tags, $node->getCacheTags());
|
||||
if ($node->getOwner()) {
|
||||
$cache_tags = Cache::mergeTags($cache_tags, $node->getOwner()->getCacheTags());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the list cache tag for nodes.
|
||||
$cache_tags = Cache::mergeTags($cache_tags, \Drupal::entityManager()->getDefinition('node')->getListCacheTags());
|
||||
|
||||
$page['tracker'] = array(
|
||||
'#rows' => $rows,
|
||||
'#header' => array(t('Type'), t('Title'), t('Author'), t('Comments'), t('Last updated')),
|
||||
'#type' => 'table',
|
||||
'#empty' => t('No content available.'),
|
||||
);
|
||||
$page['pager'] = array(
|
||||
'#type' => 'pager',
|
||||
'#weight' => 10,
|
||||
);
|
||||
$page['#sorted'] = TRUE;
|
||||
$page['#cache']['tags'] = $cache_tags;
|
||||
$page['#cache']['contexts'][] = 'user.node_grants:view';
|
||||
|
||||
// Display the reading history if that module is enabled.
|
||||
if (\Drupal::moduleHandler()->moduleExists('history')) {
|
||||
// Reading history is tracked for authenticated users only.
|
||||
if (\Drupal::currentUser()->isAuthenticated()) {
|
||||
$page['#attached']['library'][] = 'tracker/history';
|
||||
}
|
||||
$page['#cache']['contexts'][] = 'user.roles:authenticated';
|
||||
}
|
||||
|
||||
return $page;
|
||||
}
|
28
web/core/modules/tracker/tracker.routing.yml
Normal file
28
web/core/modules/tracker/tracker.routing.yml
Normal file
|
@ -0,0 +1,28 @@
|
|||
tracker.page:
|
||||
path: '/activity'
|
||||
defaults:
|
||||
_controller: '\Drupal\tracker\Controller\TrackerPage::getContent'
|
||||
_title: 'Recent content'
|
||||
requirements:
|
||||
_permission: 'access content'
|
||||
|
||||
tracker.users_recent_content:
|
||||
path: '/activity/{user}'
|
||||
defaults:
|
||||
_controller: '\Drupal\tracker\Controller\TrackerUserRecent::getContent'
|
||||
_title: 'My recent content'
|
||||
requirements:
|
||||
_permission: 'access content'
|
||||
_access_tracker_own_information: 'TRUE'
|
||||
user: \d+
|
||||
|
||||
tracker.user_tab:
|
||||
path: '/user/{user}/activity'
|
||||
defaults:
|
||||
_controller: '\Drupal\tracker\Controller\TrackerUserTab::getContent'
|
||||
_title_callback: '\Drupal\tracker\Controller\TrackerUserTab::getTitle'
|
||||
requirements:
|
||||
_permission: 'access content'
|
||||
_entity_access: 'user.view'
|
||||
user: \d+
|
||||
|
5
web/core/modules/tracker/tracker.services.yml
Normal file
5
web/core/modules/tracker/tracker.services.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
services:
|
||||
access_check.tracker.view_own:
|
||||
class: Drupal\tracker\Access\ViewOwnTrackerAccessCheck
|
||||
tags:
|
||||
- { name: access_check, applies_to: _access_tracker_own_information }
|
179
web/core/modules/tracker/tracker.views.inc
Normal file
179
web/core/modules/tracker/tracker.views.inc
Normal file
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provide views data for tracker.module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_views_data().
|
||||
*/
|
||||
function tracker_views_data() {
|
||||
$data = array();
|
||||
|
||||
$data['tracker_node']['table']['group'] = t('Tracker');
|
||||
$data['tracker_node']['table']['join'] = array(
|
||||
'node_field_data' => array(
|
||||
'type' => 'INNER',
|
||||
'left_field' => 'nid',
|
||||
'field' => 'nid',
|
||||
),
|
||||
);
|
||||
$data['tracker_node']['nid'] = array(
|
||||
'title' => t('Nid'),
|
||||
'help' => t('The node ID of the node.'),
|
||||
'field' => array(
|
||||
'id' => 'node',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'node_nid',
|
||||
'name field' => 'title',
|
||||
'numeric' => TRUE,
|
||||
'validate type' => 'nid',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'numeric',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
);
|
||||
$data['tracker_node']['published'] = array(
|
||||
'title' => t('Published'),
|
||||
'help' => t('Whether or not the node is published.'),
|
||||
'field' => array(
|
||||
'id' => 'boolean',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'boolean',
|
||||
'label' => t('Published'),
|
||||
'type' => 'yes-no',
|
||||
'accept null' => TRUE,
|
||||
'use_equal' => TRUE,
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
);
|
||||
$data['tracker_node']['changed'] = array(
|
||||
'title' => t('Updated date'),
|
||||
'help' => t('The date the node was last updated.'),
|
||||
'field' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
);
|
||||
|
||||
$data['tracker_user']['table']['group'] = t('Tracker - User');
|
||||
$data['tracker_user']['table']['join'] = array(
|
||||
'node_field_data' => array(
|
||||
'type' => 'INNER',
|
||||
'left_field' => 'nid',
|
||||
'field' => 'nid',
|
||||
),
|
||||
'user_field_data' => array(
|
||||
'type' => 'INNER',
|
||||
'left_field' => 'uid',
|
||||
'field' => 'uid',
|
||||
),
|
||||
);
|
||||
$data['tracker_user']['nid'] = array(
|
||||
'title' => t('Nid'),
|
||||
'help' => t('The node ID of the node a user created or commented on. You must use an argument or filter on UID or you will get misleading results using this field.'),
|
||||
'field' => array(
|
||||
'id' => 'node',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'node_nid',
|
||||
'name field' => 'title',
|
||||
'numeric' => TRUE,
|
||||
'validate type' => 'nid',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'numeric',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
);
|
||||
$data['tracker_user']['uid'] = array(
|
||||
'title' => t('Uid'),
|
||||
'help' => t('The user ID of a user who touched the node (either created or commented on it).'),
|
||||
'field' => array(
|
||||
'id' => 'user_name',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'user_uid',
|
||||
'name field' => 'name',
|
||||
),
|
||||
'filter' => array(
|
||||
'title' => t('Name'),
|
||||
'id' => 'user_name',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
);
|
||||
$data['tracker_user']['published'] = array(
|
||||
'title' => t('Published'),
|
||||
'help' => t('Whether or not the node is published. You must use an argument or filter on UID or you will get misleading results using this field.'),
|
||||
'field' => array(
|
||||
'id' => 'boolean',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'boolean',
|
||||
'label' => t('Published'),
|
||||
'type' => 'yes-no',
|
||||
'accept null' => TRUE,
|
||||
'use_equal' => TRUE,
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
);
|
||||
$data['tracker_user']['changed'] = array(
|
||||
'title' => t('Updated date'),
|
||||
'help' => t('The date the node was last updated or commented on. You must use an argument or filter on UID or you will get misleading results using this field.'),
|
||||
'field' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_views_data_alter().
|
||||
*/
|
||||
function tracker_views_data_alter(&$data) {
|
||||
// Provide additional uid_touch handlers which are handled by tracker
|
||||
$data['node_field_data']['uid_touch_tracker'] = array(
|
||||
'group' => t('Tracker - User'),
|
||||
'title' => t('User posted or commented'),
|
||||
'help' => t('Display nodes only if a user posted the node or commented on the node.'),
|
||||
'argument' => array(
|
||||
'field' => 'uid',
|
||||
'name table' => 'users_field_data',
|
||||
'name field' => 'name',
|
||||
'id' => 'tracker_user_uid',
|
||||
'no group by' => TRUE,
|
||||
),
|
||||
'filter' => array(
|
||||
'field' => 'uid',
|
||||
'name table' => 'users_field_data',
|
||||
'name field' => 'name',
|
||||
'id' => 'tracker_user_uid'
|
||||
),
|
||||
);
|
||||
}
|
Reference in a new issue