summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/dashboard/dashboard.css11
-rw-r--r--modules/node/node.module145
-rw-r--r--modules/node/node.test108
3 files changed, 261 insertions, 3 deletions
diff --git a/modules/dashboard/dashboard.css b/modules/dashboard/dashboard.css
index 1df2867fd..32f3fc0c7 100644
--- a/modules/dashboard/dashboard.css
+++ b/modules/dashboard/dashboard.css
@@ -147,3 +147,14 @@
width: 30px;
height: 1.6em;
}
+
+/* Recent content block */
+#dashboard #block-node-recent table,
+#dashboard #block-node-recent tr {
+ border: none;
+}
+
+#dashboard .list-all {
+ text-align: right;
+ margin: 0 10px 0 0;
+}
diff --git a/modules/node/node.module b/modules/node/node.module
index c71badf7e..e6c176c6a 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -166,6 +166,12 @@ function node_theme() {
'node_admin_overview' => array(
'variables' => array('name' => NULL, 'type' => NULL),
),
+ 'node_recent_block' => array(
+ 'variables' => array('nodes' => NULL),
+ ),
+ 'node_recent_content' => array(
+ 'variables' => array('node' => NULL),
+ ),
);
}
@@ -2007,6 +2013,9 @@ function node_block_info() {
$blocks['syndicate']['info'] = t('Syndicate');
// Not worth caching.
$blocks['syndicate']['cache'] = DRUPAL_NO_CACHE;
+
+ $blocks['recent']['info'] = t('Recent content');
+
return $blocks;
}
@@ -2014,13 +2023,145 @@ function node_block_info() {
* Implements hook_block_view().
*/
function node_block_view($delta = '') {
- $block['subject'] = t('Syndicate');
- $block['content'] = theme('feed_icon', array('url' => url('rss.xml'), 'title' => t('Syndicate')));
+ $block = array();
+ switch ($delta) {
+ case 'syndicate':
+ $block['subject'] = t('Syndicate');
+ $block['content'] = theme('feed_icon', array('url' => url('rss.xml'), 'title' => t('Syndicate')));
+ break;
+
+ case 'recent':
+ if (user_access('access content')) {
+ $block['subject'] = t('Recent content');
+ if ($nodes = node_get_recent(variable_get('node_recent_block_count', 10))) {
+ $block['content'] = theme('node_recent_block', array(
+ 'nodes' => $nodes,
+ ));
+ } else {
+ $block['content'] = t('No content available.');
+ }
+ }
+ break;
+ }
return $block;
}
/**
+ * Implements hook_block_configure().
+ */
+function node_block_configure($delta = '') {
+ $form = array();
+ if ($delta == 'recent') {
+ $form['node_recent_block_count'] = array(
+ '#type' => 'select',
+ '#title' => t('Number of recent content items to display'),
+ '#default_value' => variable_get('node_recent_block_count', 10),
+ '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 30)),
+ );
+ }
+ return $form;
+}
+
+/**
+ * Implements hook_block_save().
+ */
+function node_block_save($delta = '', $edit = array()) {
+ if ($delta == 'recent') {
+ variable_set('node_recent_block_count', $edit['node_recent_block_count']);
+ }
+}
+
+/**
+ * Find the most recent nodes that are available to the current user.
+ *
+ * @param $number
+ * (optional) The maximum number of nodes to find. Defaults to 10.
+ *
+ * @return
+ * An array of partial node objects or an empty array if there are no recent
+ * nodes visible to the current user.
+ */
+function node_get_recent($number = 10) {
+ $query = db_select('node', 'n');
+
+ if (!user_access('bypass node access')) {
+ // If the user is able to view their own unpublished nodes, allow them
+ // to see these in addition to published nodes. Check that they actually
+ // have some unpublished nodes to view before adding the condition.
+ if (user_access('view own unpublished content') && $own_unpublished = db_query('SELECT nid FROM {node} WHERE uid = :uid AND status = :status', array(':uid' => $GLOBALS['user']->uid, ':status' => NODE_NOT_PUBLISHED))->fetchCol()) {
+ $query->condition(db_or()
+ ->condition('n.status', NODE_PUBLISHED)
+ ->condition('n.nid', $own_unpublished, 'IN')
+ );
+ }
+ else {
+ // If not, restrict the query to published nodes.
+ $query->condition('n.status', NODE_PUBLISHED);
+ }
+ }
+ $nids = $query
+ ->fields('n', array('nid'))
+ ->orderBy('changed', 'DESC')
+ ->range(0, $number)
+ ->addTag('node_access')
+ ->execute()
+ ->fetchCol();
+
+ $nodes = node_load_multiple($nids);
+
+ return $nodes ? $nodes : array();
+}
+
+/**
+ * Returns a formatted list of recent nodes.
+ *
+ * @return
+ * The recent content table HTML.
+ * @ingroup themeable
+ */
+function theme_node_recent_block($variables) {
+ $rows = array();
+ $output = '';
+
+ $l_options = array('query' => drupal_get_destination());
+ foreach ($variables['nodes'] as $node) {
+ $row = array();
+ $row[] = theme('node_recent_content', array('node' => $node));
+ $row[] = node_access('update', $node) ? l(t('edit'), 'node/' . $node->nid . '/edit', $l_options) : '';
+ $row[] = node_access('delete', $node) ? l(t('delete'), 'node/' . $node->nid . '/delete', $l_options) : '';
+ $rows[] = $row;
+ }
+
+ if ($rows) {
+ $output = theme('table', array('rows' => $rows));
+ $output .= '<div class="list-all">' . l(t('Show all content'), 'admin/content') . '</div>';
+ }
+
+ return $output;
+}
+
+/**
+ * Returns a formatted recent node to be displayed in the recent content block.
+ *
+ * @return
+ * The recent content node's HTML.
+ * @ingroup themeable
+ */
+function theme_node_recent_content($variables) {
+ $node = $variables['node'];
+
+ $output = '<div class="node-title">';
+ $output .= l($node->title, 'node/' . $node->nid);
+ $output .= theme('mark', array('type' => node_mark($node->nid, $node->changed)));
+ $output .= '</div><div class="node-author">';
+ $output .= theme('username', array('account' => user_load($node->uid)));
+ $output .= '</div>';
+
+ return $output;
+}
+
+/**
* A generic function for generating RSS feeds from a set of nodes.
*
* @param $nids
diff --git a/modules/node/node.test b/modules/node/node.test
index df0b29bc1..4cd0a4859 100644
--- a/modules/node/node.test
+++ b/modules/node/node.test
@@ -378,7 +378,7 @@ class NodeCreationTestCase extends DrupalWebTestCase {
// Check that the failed rollback was logged.
$records = db_query("SELECT wid FROM {watchdog} WHERE message LIKE 'Explicit rollback failed%'")->fetchAll();
- $this->assertTrue(count($records) > 0, t('Transactions not supported, and rollback error logged to watchdog.'));
+ $this->assertTrue(count($records) > 0, t('Transactions not supported, and rollback error logged to watchdog.'));
}
// Check that the rollback error was logged.
@@ -1170,3 +1170,109 @@ class NodeFeedTestCase extends DrupalWebTestCase {
$this->assertTrue(strpos($output, '<copyright>Drupal is a registered trademark of Dries Buytaert.</copyright>') !== FALSE);
}
}
+
+/**
+ * Functional tests for the node module blocks.
+ */
+class NodeBlockFunctionalTest extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Node blocks',
+ 'description' => 'Test node block functionality.',
+ 'group' => 'Node',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('node');
+
+ // Create users and test node.
+ $this->admin_user = $this->drupalCreateUser(array('administer content types', 'administer nodes', 'administer blocks'));
+ $this->web_user = $this->drupalCreateUser(array('access content', 'create article content'));
+ }
+
+ /**
+ * Test the recent comments block.
+ */
+ function testRecentNodeBlock() {
+ $this->drupalLogin($this->admin_user);
+
+ // Disallow anonymous users to view content.
+ user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
+ 'access content' => FALSE,
+ ));
+
+ // Set the block to a region to confirm block is available.
+ $edit = array(
+ 'node_recent[region]' => 'sidebar_first',
+ );
+ $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
+ $this->assertText(t('The block settings have been updated.'), t('Block saved to first sidebar region.'));
+
+ // Set block title and variables.
+ $block = array(
+ 'title' => $this->randomName(),
+ 'node_recent_block_count' => 2,
+ );
+ $this->drupalPost('admin/structure/block/manage/node/recent/configure', $block, t('Save block'));
+ $this->assertText(t('The block configuration has been saved.'), t('Block saved.'));
+
+ // Test that block is not visible without nodes
+ $this->drupalGet('');
+ $this->assertText(t('No content available.'), t('Block with "No content available." found.'));
+
+ // Add some test nodes.
+ $default_settings = array('uid' => $this->web_user->uid, 'type' => 'article');
+ $node1 = $this->drupalCreateNode($default_settings);
+ $node2 = $this->drupalCreateNode($default_settings);
+ $node3 = $this->drupalCreateNode($default_settings);
+
+ // Change the changed time for node so that we can test ordering.
+ db_update('node')
+ ->fields(array(
+ 'changed' => $node1->changed + 100,
+ ))
+ ->condition('nid', $node2->nid)
+ ->execute();
+ db_update('node')
+ ->fields(array(
+ 'changed' => $node1->changed + 200,
+ ))
+ ->condition('nid', $node3->nid)
+ ->execute();
+
+ // Test that a user without the 'access content' permission cannot
+ // see the block.
+ $this->drupalLogout();
+ $this->drupalGet('');
+ $this->assertNoText($block['title'], t('Block was not found.'));
+
+ // Test that only the 2 latest nodes are shown.
+ $this->drupalLogin($this->web_user);
+ $this->assertNoText($node1->title, t('Node not found in block.'));
+ $this->assertText($node2->title, t('Node found in block.'));
+ $this->assertText($node3->title, t('Node found in block.'));
+
+ // Check to make sure nodes are in the right order.
+ $this->assertTrue($this->xpath('//div[@id="block-node-recent"]/div/table/tbody/tr[position() = 1]/td/div/a[text() = "' . $node3->title . '"]'), t('Nodes were ordered correctly in block.'));
+
+ // Set the number of recent nodes to show to 10.
+ $this->drupalLogout();
+ $this->drupalLogin($this->admin_user);
+ $block = array(
+ 'node_recent_block_count' => 10,
+ );
+ $this->drupalPost('admin/structure/block/manage/node/recent/configure', $block, t('Save block'));
+ $this->assertText(t('The block configuration has been saved.'), t('Block saved.'));
+
+ // Post an additional node.
+ $node4 = $this->drupalCreateNode($default_settings);
+
+ // Test that all four nodes are shown.
+ $this->drupalGet('');
+ $this->assertText($node1->title, t('Node found in block.'));
+ $this->assertText($node2->title, t('Node found in block.'));
+ $this->assertText($node3->title, t('Node found in block.'));
+ $this->assertText($node4->title, t('Node found in block.'));
+ }
+}