node.module 47.3 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
2
// $Id$
Dries's avatar
 
Dries committed
3

4 5
define('NODE_NEW_LIMIT', time() - 30 * 24 * 60 * 60);

Dries's avatar
 
Dries committed
6
function node_help($section = 'admin/help#node') {
Dries's avatar
 
Dries committed
7
  global $mod;
Dries's avatar
 
Dries committed
8
  $output = '';
9 10 11

  switch ($section) {

Dries's avatar
 
Dries committed
12
    case 'admin/help#node':
Dries's avatar
 
Dries committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
      $output .= t("
      <h3>Nodes</h3>
      <p>The core of the Drupal system is the node. All of the contents of the system are placed in nodes, or extensions of nodes.
      A base node contains:<dl>
      <dt>A Title</dt><dd>Up to 128 characters of text that titles the node.</dd>
      <dt>A Teaser</dt><dd>A small block of text that is meant to get you interested in the rest of node. Drupal will automatically pull a small amount of the body of the node to make the teaser (To configure how long the teaser will be <a href=\"%teaser\">click here</a>). The teaser can be changed if you don't like what Drupal grabs.</dd>
      <dt>The Body</dt><dd>The main text that comprises your content.</dd>
      <dt>A Type</dt><dd>What kind of node is this? Blog, book, forum, comment, unextended, etc.</dd>
      <dt>An Author</dt><dd>The author's name. It will either be \"anonymous\" or a valid user. You <i>cannot</i> set it to an arbitrary value.</dd>
      <dt>Authored on</dt><dd>The date the node was written.</dd>
      <dt>Changed</dt><dd>The last time this node was changed.</dd>
      <dt>Static on front page</dt><dd>The front page is configured to show the teasers from only a few of the total nodes you have on your site (To configure how many teasers <a href=\"%teaser\">click here</a>), but if you think a node is important enough that you want it to stay on the front page enable this.</dd>
      <dt>Allow user comments</dt><dd>A node can have comments. These comments can be written by other users (Read-write), or only by admins (Read-only).</dd>
      <dt>Attributes</dt><dd>A way to sort nodes.</dd>
      <dt>Revisions</dt><dd>Drupal has a revision system so that you can \"roll back\" to an older version of a post if the new version is not what you want.</dd>
      <dt>Promote to front page</dt><dd>To get people to look at the new stuff on your site you can choose to move it to the front page.</dd>
      <dt>In moderation queue</dt><dd>Drupal has a moderation system. If it is active, a node is in one of three states: approved and published, approved and unpublished, and awaiting approval. If you are moderating a node it should be in the moderation queue.</dd>
      <dt>Votes</dt><dd>If you are moderating a node this counts how many votes the node has gotten. Once a node gets a certain number of vote it will either be approved or dropped.
      <dt>Score</dt><dd>The score of the node is gotten by the votes it is given.</dd>
      <dt>Users</dt><dd>The list of users who have voted on a moderated node.</dd>
      <dt>Published</dt><dd>When using Drupal's moderation system a node remains unpublished -- unavaliable to non-moderators -- until it is marked Published.</dd></dl>
      <p>Now that you know what is in a node, here are some of the types of nodes available.</p>", array("%teaser" => url("admin/system/modules/node")));
Dries's avatar
 
Dries committed
35

Dries's avatar
 
Dries committed
36
      if ($mod == 'admin') {
Dries's avatar
 
Dries committed
37
        foreach (node_list() as $type) {
Dries's avatar
 
Dries committed
38
          $output .= '<h3>'. t('Node type: %module', array('%module' => node_invoke($type, 'node_name'))). '</h3>';
39
          $output .= implode("\n", module_invoke_all('help', 'node/add#'. $type));
40
        }
Dries's avatar
 
Dries committed
41
      }
42 43
      break;

Dries's avatar
 
Dries committed
44
    case 'admin/system/modules#description':
Dries's avatar
 
Dries committed
45
      $output = t('The core that allows content to be submitted to the site.');
46 47
      break;
    case 'admin/system/modules/node':
Dries's avatar
 
Dries committed
48
      $output = t('Settings for the core of Drupal. Almost everything is a node so these settings will affect most of the site.');
49 50
      break;
    case 'admin/node':
Dries's avatar
 
Dries committed
51
      $output = t("Below is a list of all of the nodes in your site. Other forms of content are listed elsewhere (e.g. <a href=\"%comments\">comments</a>).<br />Clicking a title views that node, while clicking an author's name edits their user information.<br />Other node-related tasks are available from the menu on the left.", array('%comments' => url('admin/comment')));
52 53
      break;
    case 'admin/node/search':
Dries's avatar
 
Dries committed
54
      $output = t("Enter a simple pattern to search for a post. This can include the wildcard character *.<br />For example, a search for \"br*\" might return \"bread bakers\", \"our daily bread\" and \"brenda\".");
55 56
      break;
    case 'admin/node/settings':
Dries's avatar
 
Dries committed
57
      $output = t('This page lets you set the defaults used during creation of nodes for all the different node types.<br /><strong>comment:</strong> Read/write setting for comments.<br /><strong>publish:</strong> Is this node publicly viewable, has it been published?<br /><strong>promote:</strong> Is this node to be promoted to the front page?<br /><strong>moderate:</strong> Does this node need approval before it can be viewed?<br /><strong>static:</strong> Is this node always visible on the front page?<br /><strong>revision:</strong> Will this node go into the revision system allowing multiple versions to be saved?');
58 59
      break;

Dries's avatar
 
Dries committed
60
  }
Dries's avatar
 
Dries committed
61 62

  return $output;
Dries's avatar
 
Dries committed
63 64
}

65
function node_cron() {
Dries's avatar
 
Dries committed
66
  db_query('DELETE FROM {history} WHERE timestamp < %d', NODE_NEW_LIMIT);
67 68
}

Dries's avatar
 
Dries committed
69
function node_help_page() {
Dries's avatar
 
Dries committed
70
  print theme('page', node_help());
Dries's avatar
 
Dries committed
71 72 73
}


Dries's avatar
 
Dries committed
74 75 76 77
/*
** Accepts a DB result object which can be used to fetch node objects.
** Returns an HTML list suitable as content for a block.
*/
Dries's avatar
 
Dries committed
78 79
function node_title_list($result, $title = NULL) {
  while ($node = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
80 81
    $number = module_invoke('comment', 'num_all', $node->nid);
    $items[] = l($node->title, "node/view/$node->nid", array('title' => format_plural($number, '%count comment', '%count comments')));
Dries's avatar
 
Dries committed
82 83
  }

Dries's avatar
 
Dries committed
84
  return theme('node_list', $items, $title);
Dries's avatar
 
Dries committed
85 86
}

Dries's avatar
 
Dries committed
87
function theme_node_list($items, $title = NULL) {
Dries's avatar
 
Dries committed
88
  return theme('item_list', $items, $title);
Dries's avatar
 
Dries committed
89 90
}

Dries's avatar
 
Dries committed
91 92 93 94 95
// Update the 'last viewed' timestamp of the specified node for current user.
function node_tag_new($nid) {
  global $user;

  if ($user->uid) {
Dries's avatar
 
Dries committed
96
    $result = db_query('SELECT timestamp FROM {history} WHERE uid = %d AND nid = %d', $user->uid, $nid);
Dries's avatar
 
Dries committed
97
    if (db_fetch_object($result)) {
Dries's avatar
 
Dries committed
98
      db_query('UPDATE {history} SET timestamp = %d WHERE uid = %d AND nid = %d', time(), $user->uid, $nid);
Dries's avatar
 
Dries committed
99 100
    }
    else {
Dries's avatar
 
Dries committed
101
      db_query('INSERT INTO {history} (uid, nid, timestamp) VALUES (%d, %d, %d)', $user->uid, $nid, time());
Dries's avatar
 
Dries committed
102 103 104 105 106 107 108 109 110 111 112
    }
  }
}

/*
** Retrieves the timestamp at which the current user last viewed the
** specified node.
*/
function node_last_viewed($nid) {
  global $user;

Dries's avatar
 
Dries committed
113
  $history = db_fetch_object(db_query("SELECT timestamp FROM {history} WHERE uid = '$user->uid' AND nid = %d", $nid));
114
  return ($history->timestamp ? $history->timestamp : NODE_NEW_LIMIT);
Dries's avatar
 
Dries committed
115 116 117
}

/**
Dries's avatar
 
Dries committed
118 119
 * Determines whether the supplied timestamp is newer than the user's last view
 * of a given node
Dries's avatar
 
Dries committed
120
 *
121 122
 * @param $nid node-id whose history supplies the 'last viewed' timestamp
 * @param $timestamp time which is compared against node's 'last viewed'
Dries's avatar
 
Dries committed
123 124
 *   timestamp
 */
Dries's avatar
 
Dries committed
125 126 127 128
function node_is_new($nid, $timestamp) {
  global $user;
  static $cache;

Dries's avatar
Dries committed
129
  if (!isset($cache[$nid])) {
Dries's avatar
 
Dries committed
130
    if ($user->uid) {
Dries's avatar
 
Dries committed
131
      $history = db_fetch_object(db_query('SELECT timestamp FROM {history} WHERE uid = %d AND nid = %d', $user->uid, $nid));
Dries's avatar
 
Dries committed
132 133 134 135 136 137 138
      $cache[$nid] = $history->timestamp ? $history->timestamp : 0;
    }
    else {
      $cache[$nid] = time();
    }
  }

139
  return ($timestamp > $cache[$nid] && $timestamp > NODE_NEW_LIMIT);
Dries's avatar
 
Dries committed
140 141
}

Dries's avatar
 
Dries committed
142 143
function node_teaser($body) {

Dries's avatar
 
Dries committed
144
  $size = variable_get('teaser_length', 600);
Dries's avatar
 
Dries committed
145 146 147 148 149 150 151 152 153

  /*
  ** If the size is zero, teasers are disabled so we
  ** return the entire body.
  */

  if ($size == 0) {
    return $body;
  }
Dries's avatar
 
Dries committed
154 155

  /*
Dries's avatar
 
Dries committed
156
  ** If a valid delimiter has been specified, use it to
Dries's avatar
 
Dries committed
157 158
  ** chop of the teaser.  The delimiter can be outside
  ** the allowed range but no more than a factor two.
Dries's avatar
 
Dries committed
159 160
  */

Dries's avatar
 
Dries committed
161
  $delimiter = strpos($body, '<!--break-->');
Dries's avatar
 
Dries committed
162
  if ($delimiter > 0) {
Dries's avatar
 
Dries committed
163 164 165
    return substr($body, 0, $delimiter);
  }

Dries's avatar
 
Dries committed
166 167 168 169 170 171 172 173
  /*
  ** If we have a short body, return the entire body:
  */

  if (strlen($body) < $size) {
    return $body;
  }

Dries's avatar
 
Dries committed
174 175 176 177
  /*
  ** In some cases no delimiter has been specified (eg.
  ** when posting using the Blogger API) in which case
  ** we try to split at paragraph boundaries.
Dries's avatar
 
Dries committed
178 179
  */

Dries's avatar
 
Dries committed
180
  if ($length = strpos($body, '</p>', $size)) {
Dries's avatar
 
Dries committed
181
    return substr($body, 0, $length + 4);
Dries's avatar
 
Dries committed
182 183
  }

Dries's avatar
 
Dries committed
184
  if ($length = strpos($body, '<br />', $size)) {
Dries's avatar
 
Dries committed
185
    return substr($body, 0, $length);
Dries's avatar
 
Dries committed
186 187
  }

Dries's avatar
 
Dries committed
188
  if ($length = strpos($body, '<br>', $size)) {
Dries's avatar
 
Dries committed
189 190 191
    return substr($body, 0, $length);
  }

192
  if ($length = strpos($body, "\n", $size)) {
Dries's avatar
 
Dries committed
193
    return substr($body, 0, $length);
Dries's avatar
 
Dries committed
194 195
  }

Dries's avatar
 
Dries committed
196
  /*
Dries's avatar
 
Dries committed
197
  ** When even the first paragraph is too long, try to
Dries's avatar
 
Dries committed
198
  ** split at the end of the next sentence.
Dries's avatar
 
Dries committed
199 200
  */

Dries's avatar
 
Dries committed
201
  if ($length = strpos($body, '. ', $size)) {
Dries's avatar
 
Dries committed
202 203 204
    return substr($body, 0, $length + 1);
  }

Dries's avatar
 
Dries committed
205
  if ($length = strpos($body, '! ', $size)) {
Dries's avatar
 
Dries committed
206 207 208
    return substr($body, 0, $length + 1);
  }

Dries's avatar
 
Dries committed
209
  if ($length = strpos($body, '? ', $size)) {
Dries's avatar
 
Dries committed
210 211 212 213 214 215
    return substr($body, 0, $length + 1);
  }

  /*
  ** Nevermind, we split it the hard way ...
  */
Dries's avatar
 
Dries committed
216

Dries's avatar
 
Dries committed
217
  return substr($body, 0, $size);
Dries's avatar
 
Dries committed
218 219
}

Dries's avatar
 
Dries committed
220 221 222 223 224 225 226 227 228 229

/*
 * Determines the module that defines the node type of the given node.
 *
 * @param &$node
 *   Either a node object, node array, or a string containing the node type.
 * @return
 *   A string containing the name of the defining module.
 */
function node_get_module_name($node) {
Dries's avatar
 
Dries committed
230
  if (is_array($node)) {
Dries's avatar
 
Dries committed
231 232
    if ($pos = strpos($node['type'], '/')) {
      return substr($node['type'], 0, $pos);
Dries's avatar
 
Dries committed
233
    } else {
Dries's avatar
 
Dries committed
234
      return $node['type'];
Dries's avatar
 
Dries committed
235
    }
Dries's avatar
 
Dries committed
236 237
  }
  else if (is_object($node)) {
Dries's avatar
 
Dries committed
238
    if ($pos = strpos($node->type, '/')) {
Dries's avatar
 
Dries committed
239 240 241 242
      return substr($node->type, 0, $pos);
    } else {
      return $node->type;
    }
Dries's avatar
 
Dries committed
243 244
  }
  else if (is_string($node)) {
Dries's avatar
 
Dries committed
245
    if ($pos = strpos($node, '/')) {
Dries's avatar
 
Dries committed
246 247 248 249
      return substr($node, 0, $pos);
    } else {
      return $node;
    }
Dries's avatar
 
Dries committed
250
  }
Dries's avatar
 
Dries committed
251
}
Dries's avatar
 
Dries committed
252 253 254 255 256

/*
 * Get a list of all the defined node types.
 *
 * @return
Dries's avatar
 
Dries committed
257
 *   An list of all node types.
Dries's avatar
 
Dries committed
258 259 260 261
 */
function node_list() {
  $types = array();
  foreach (module_list() as $module) {
Dries's avatar
 
Dries committed
262 263
    if (module_hook($module, 'node_name')) {
      $module_types = module_invoke($module, 'node_types');
Dries's avatar
 
Dries committed
264 265
      if ($module_types) {
        foreach ($module_types as $type) {
Dries's avatar
 
Dries committed
266
          $types[] = $type;
Dries's avatar
 
Dries committed
267 268
        }
      } else {
Dries's avatar
 
Dries committed
269
        $types[] = $module;
Dries's avatar
 
Dries committed
270 271 272 273
      }
    }
  }
  return $types;
Dries's avatar
 
Dries committed
274
}
Dries's avatar
 
Dries committed
275 276 277 278 279 280 281 282 283 284 285 286

/*
 * Determine whether a node hook exists.
 *
 * @param &$node
 *   Either a node object, node array, or a string containing the node type.
 * @param $hook
 *   A string containing the name of the hook.
 * @return
 *   TRUE iff the $hook exists in the node type of $node.
 */
function node_hook(&$node, $hook) {
287
  $function = node_get_module_name($node) ."_$hook";
Dries's avatar
 
Dries committed
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304

  return function_exists($function);
}

/*
 * Invoke a node hook.
 *
 * @param &$node
 *   Either a node object, node array, or a string containing the node type.
 * @param $hook
 *   A string containing the name of the hook.
 * @param $a2, $a3, $a4
 *   Arguments to pass on to the hook, after the $node argument.
 * @return
 *   The returned value of the invoked hook is returned.
 */
function node_invoke(&$node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
305
  $function = node_get_module_name($node) ."_$hook";
Dries's avatar
 
Dries committed
306 307

  if (function_exists($function)) {
Dries's avatar
 
Dries committed
308
    return ($function($node, $a2, $a3, $a4));
Dries's avatar
 
Dries committed
309 310 311
  }
}

Dries's avatar
 
Dries committed
312 313 314
function node_invoke_nodeapi(&$node, $op, $arg = 0) {
  $return = array();
  foreach (module_list() as $name) {
Dries's avatar
 
Dries committed
315
    $function = $name .'_nodeapi';
Dries's avatar
 
Dries committed
316 317 318 319 320 321 322 323 324 325
    if (function_exists($function)) {
      $result = $function($node, $op, $arg);
      if (isset($result)) {
        $return = array_merge($return, $result);
      }
    }
  }
  return $return;
}

Dries's avatar
 
Dries committed
326
function node_load($conditions, $revision = -1) {
Dries's avatar
 
Dries committed
327 328 329 330 331 332

  /*
  ** Turn the conditions into a query:
  */

  foreach ($conditions as $key => $value) {
Dries's avatar
 
Dries committed
333
    $cond[] = 'n.'. check_query($key) ." = '". check_query($value) ."'";
Dries's avatar
 
Dries committed
334 335 336 337 338 339
  }

  /*
  ** Retrieve the node:
  */

Dries's avatar
 
Dries committed
340
  $node = db_fetch_object(db_query('SELECT n.*, u.uid, u.name, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid WHERE '. implode(' AND ', $cond)));
Dries's avatar
 
Dries committed
341
  $node = drupal_unpack($node);
Dries's avatar
 
Dries committed
342 343

  /*
Dries's avatar
 
Dries committed
344
  ** Unserialize the revisions and user data fields:
Dries's avatar
 
Dries committed
345 346 347 348 349 350 351 352 353 354 355
  */

  if ($node->revisions) {
    $node->revisions = unserialize($node->revisions);
  }

  /*
  ** Call the node specific callback (if any) and piggy-back the
  ** results to the node or overwrite some values:
  */

Dries's avatar
 
Dries committed
356
  if ($extra = node_invoke($node, 'load')) {
Dries's avatar
 
Dries committed
357 358 359 360 361
    foreach ($extra as $key => $value) {
      $node->$key = $value;
    }
  }

Dries's avatar
 
Dries committed
362 363 364 365
  /*
  ** Return the desired revision
  */
  if ($revision != -1 && isset($node->revisions[$revision])) {
Dries's avatar
 
Dries committed
366
    $node = $node->revisions[$revision]['node'];
Dries's avatar
 
Dries committed
367 368
  }

Dries's avatar
 
Dries committed
369 370 371
  return $node;
}

372
function node_save($node) {
Dries's avatar
 
Dries committed
373

374 375 376
  /*
  ** Fetch fields to save to node table:
  */
Dries's avatar
 
Dries committed
377
  $fields = node_invoke_nodeapi($node, 'fields');
Dries's avatar
 
Dries committed
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396

  /*
  ** Serialize the revisions field:
  */

  if ($node->revisions) {
    $node->revisions = serialize($node->revisions);
  }

  /*
  ** Apply filters to some default node fields:
  */

  if (empty($node->nid)) {

    /*
    ** Insert a new node:
    */

Dries's avatar
 
Dries committed
397
    // Set some required fields:
398 399 400
    if (!$node->created) {
      $node->created = time();
    }
Dries's avatar
 
Dries committed
401
    $node->changed = time();
Dries's avatar
 
Dries committed
402
    $node->nid = db_next_id('{node}_nid');
Dries's avatar
 
Dries committed
403

Dries's avatar
 
Dries committed
404
    // Prepare the query:
Dries's avatar
 
Dries committed
405 406 407
    foreach ($node as $key => $value) {
      if (in_array($key, $fields)) {
        $k[] = check_query($key);
Dries's avatar
 
Dries committed
408 409
        $v[] = $value;
        $s[] = "'%s'";
Dries's avatar
 
Dries committed
410 411 412
      }
    }

Dries's avatar
 
Dries committed
413
    $keysfmt = implode(', ', $s);
Dries's avatar
 
Dries committed
414 415 416
    // need to quote the placeholders for the values
    $valsfmt = "'". implode("', '", $s) ."'";

Dries's avatar
 
Dries committed
417
    // Insert the node into the database:
Dries's avatar
 
Dries committed
418
    db_query("INSERT INTO {node} (". implode(", ", $k) .") VALUES(". implode(", ", $s) .")", $v);
Dries's avatar
 
Dries committed
419

Dries's avatar
 
Dries committed
420
    // Call the node specific callback (if any):
Dries's avatar
 
Dries committed
421 422
    node_invoke($node, 'insert');
    node_invoke_nodeapi($node, 'insert');
Dries's avatar
 
Dries committed
423 424 425 426 427 428 429
  }
  else {

    /*
    ** Update an existing node:
    */

Dries's avatar
 
Dries committed
430
    // Set some required fields:
Dries's avatar
 
Dries committed
431 432
    $node->changed = time();

Dries's avatar
 
Dries committed
433
    // Prepare the query:
Dries's avatar
 
Dries committed
434 435
    foreach ($node as $key => $value) {
      if (in_array($key, $fields)) {
Dries's avatar
 
Dries committed
436 437
        $q[] = check_query($key) ." = '%s'";
        $v[] = $value;
Dries's avatar
 
Dries committed
438 439 440
      }
    }

Dries's avatar
 
Dries committed
441
    // Update the node in the database:
Dries's avatar
 
Dries committed
442
    db_query("UPDATE {node} SET ". implode(', ', $q) ." WHERE nid = '$node->nid'", $v);
Dries's avatar
 
Dries committed
443

Dries's avatar
 
Dries committed
444
    // Call the node specific callback (if any):
Dries's avatar
 
Dries committed
445 446
    node_invoke($node, 'update');
    node_invoke_nodeapi($node, 'update');
Dries's avatar
 
Dries committed
447 448
  }

Dries's avatar
 
Dries committed
449
  /*
Dries's avatar
 
Dries committed
450 451
  ** Clear the cache so an anonymous poster can see the node being
  ** added or updated.
Dries's avatar
 
Dries committed
452 453 454 455
  */

  cache_clear_all();

Dries's avatar
 
Dries committed
456 457 458 459 460 461 462 463
  /*
  ** Return the node ID:
  */

  return $node->nid;

}

Dries's avatar
 
Dries committed
464
function node_view($node, $main = 0, $page = 0) {
Dries's avatar
 
Dries committed
465

Dries's avatar
 
Dries committed
466
  $node = array2object($node);
Dries's avatar
 
Dries committed
467

Dries's avatar
 
Dries committed
468 469
  /*
  ** Remove the delimiter (if any) that seperates the teaser from the
Dries's avatar
Dries committed
470
  ** body. TODO: this strips legitimate uses of '<!--break-->' also.
Dries's avatar
 
Dries committed
471 472
  */

Dries's avatar
 
Dries committed
473
  $node->body = str_replace('<!--break-->', '', $node->body);
Dries's avatar
 
Dries committed
474

Dries's avatar
 
Dries committed
475
  /*
Dries's avatar
 
Dries committed
476
  ** The 'view' hook can be implemented to overwrite the default function
Dries's avatar
 
Dries committed
477 478 479
  ** to display nodes.
  */

Dries's avatar
 
Dries committed
480 481
  if (node_hook($node, 'view')) {
    return node_invoke($node, 'view', $main, $page);
Dries's avatar
 
Dries committed
482 483 484 485 486 487 488
  }
  else {

    /*
    ** Default behavior:
    */

Dries's avatar
 
Dries committed
489
    return theme('node', node_prepare($node, $main), $main, $page);
Dries's avatar
 
Dries committed
490 491
  }
}
Dries's avatar
 
Dries committed
492

Dries's avatar
 
Dries committed
493 494 495
function node_prepare($node, $main = 0) {
  if ($main == 0) {
    $node->body = check_output($node->body);
Dries's avatar
 
Dries committed
496 497 498
  }
  else {
    $node->teaser = check_output($node->teaser);
Dries's avatar
 
Dries committed
499
  }
Dries's avatar
 
Dries committed
500
  return $node;
Dries's avatar
 
Dries committed
501 502
}

Dries's avatar
 
Dries committed
503 504
function node_show($node, $cid) {

Dries's avatar
 
Dries committed
505
  if (node_access('view', $node)) {
Dries's avatar
 
Dries committed
506

Dries's avatar
 
Dries committed
507
    $output = node_view($node, 0, 1);
Dries's avatar
 
Dries committed
508

Dries's avatar
 
Dries committed
509
    if (function_exists('comment_render') && $node->comment) {
Dries's avatar
 
Dries committed
510
      $output .= comment_render($node, $cid);
Dries's avatar
 
Dries committed
511
    }
Dries's avatar
 
Dries committed
512 513 514 515 516 517

    /*
    ** Update the history table, stating that this user viewed this node.
    */

    node_tag_new($node->nid);
Dries's avatar
 
Dries committed
518 519

    return $output;
Dries's avatar
 
Dries committed
520
  }
Dries's avatar
 
Dries committed
521 522 523
  else {
    drupal_set_message(message_access());
  }
Dries's avatar
 
Dries committed
524 525
}

Dries's avatar
 
Dries committed
526 527
function node_access($op, $node = 0) {

Dries's avatar
 
Dries committed
528
  if (user_access('administer nodes')) {
Dries's avatar
 
Dries committed
529
    return 1;
Dries's avatar
 
Dries committed
530 531
  }

Dries's avatar
 
Dries committed
532 533 534
  /*
  ** Convert the node to an object if necessary:
  */
Dries's avatar
 
Dries committed
535

Dries's avatar
 
Dries committed
536
  $node = array2object($node);
Dries's avatar
 
Dries committed
537

Dries's avatar
 
Dries committed
538 539
  // Can't use node_invoke:
  // the access hook takes the $op parameter before the $node parameter.
Dries's avatar
 
Dries committed
540
  return module_invoke(node_get_module_name($node), 'access', $op, $node);
Dries's avatar
 
Dries committed
541 542
}

Dries's avatar
 
Dries committed
543
function node_perm() {
Dries's avatar
 
Dries committed
544
  return array('administer nodes', 'access content');
Dries's avatar
 
Dries committed
545 546
}

Dries's avatar
 
Dries committed
547 548
function node_search($keys) {

Kjartan's avatar
Kjartan committed
549 550 551
  // Return the results of performing a search using the indexed search
  // for this particular type of node.
  //
Dries's avatar
 
Dries committed
552
  // Pass an array to the 'do_search' function which dictates what it
Kjartan's avatar
Kjartan committed
553 554 555 556 557 558 559 560
  // will search through, and what it will search for
  //
  // "keys"'s value is the keywords entered by the user
  //
  // "type"'s value is used to identify the node type in the search
  // index.
  //
  // "select"'s value is used to relate the data from the specific nodes
Dries's avatar
 
Dries committed
561
  // table to the data that the search_index table has in it, and the the
Kjartan's avatar
Kjartan committed
562 563
  // do_search functino will rank it.
  //
Dries's avatar
 
Dries committed
564
  // The select must always provide the following fields - lno, title,
Kjartan's avatar
Kjartan committed
565 566
  // created, uid, name, count
  //
Dries's avatar
 
Dries committed
567
  $find = do_search(array('keys' => $keys, 'type' => 'node', 'select' => "select s.lno as lno, n.title as title, n.created as created, u.uid as uid, u.name as name, s.count as count FROM {search_index} s, {node} n INNER JOIN {users} u ON n.uid = u.uid WHERE s.lno = n.nid AND s.type = 'node' AND s.word like '%' AND n.status = 1"));
Dries's avatar
 
Dries committed
568

Dries's avatar
 
Dries committed
569
  return array(t('Matching nodes ranked in order of relevance'), $find);
Dries's avatar
 
Dries committed
570 571
}

572
function node_settings() {
Dries's avatar
 
Dries committed
573 574 575
  $output .= form_select(t('Number of posts on main page'), 'default_nodes_main', variable_get('default_nodes_main', 10), array(1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 =>  5, 6 => 6, 7 => 7, 8 => 8, 9 => 9, 10 => 10, 15 => 15, 20 => 20, 25 => 25, 30 => 30), t('The default maximum number of posts to display per page on overview pages such as the main page.'));
  $output .= form_select(t('Length of trimmed posts'), 'teaser_length', variable_get('teaser_length', 600), array(0 => t('Unlimited'), 200 => t('200 characters'), 400 => t('400 characters'), 600 => t('600 characters'), 800 => t('800 characters'), 1000 => t('1000 characters'), 1200 => t('1200 characters'), 1400 => t('1400 characters'), 1600 => t('1600 characters'), 1800 => t('1800 characters'), 2000 => t('2000 characters')), t("The maximum number of characters used in the trimmed version of a post.  Drupal will use this setting to determine at which offset long posts should be trimmed.  The trimmed version of a post is typically used as a teaser when displaying the post on the main page, in XML feeds, etc.  To disable teasers, set to 'Unlimited'."));
  $output .= form_radios(t('Preview post'), 'node_preview', variable_get('node_preview', 0), array(t('Optional'), t('Required')), t('Must users preview posts before submitting?'));
Dries's avatar
 
Dries committed
576

Dries's avatar
 
Dries committed
577 578 579
  return $output;
}

Dries's avatar
 
Dries committed
580
function node_comment_mode($nid) {
Dries's avatar
 
Dries committed
581 582
  static $comment_mode;
  if (!isset($comment_mode[$nid])) {
Dries's avatar
 
Dries committed
583
    $comment_mode[$nid] = db_result(db_query('SELECT comment FROM {node} WHERE nid = %d', $nid));
Dries's avatar
 
Dries committed
584 585
  }
  return $comment_mode[$nid];
Dries's avatar
 
Dries committed
586 587
}

588
function node_link($type, $node = 0, $main = 0) {
Dries's avatar
 
Dries committed
589

Dries's avatar
 
Dries committed
590 591
  $links = array();

Dries's avatar
 
Dries committed
592
  if ($type == 'node') {
Kjartan's avatar
Kjartan committed
593 594 595
    if ($node->links) {
      $links = $node->links;
    }
Dries's avatar
 
Dries committed
596

Dries's avatar
 
Dries committed
597
    if ($main == 1 && $node->teaser && strlen($node->teaser) != strlen($node->body)) {
Dries's avatar
 
Dries committed
598
      $links[] = l(t('read more'), "node/view/$node->nid", array('title' => t('Read the rest of this posting.'), 'class' => 'read-more'));
Dries's avatar
 
Dries committed
599
    }
Dries's avatar
 
Dries committed
600

Dries's avatar
 
Dries committed
601 602
    if (user_access('administer nodes')) {
      $links[] = l(t('administer'), "admin/node/edit/$node->nid", array('title' => t('Administer this node.')));
Dries's avatar
 
Dries committed
603 604
    }

Dries's avatar
 
Dries committed
605 606
    if (user_access('administer nodes') && $node->revisions) {
      $links[] = l(t('revisions'), "node/revisions/$node->nid", array('title' => t('Administer revisions.')));
Dries's avatar
 
Dries committed
607
    }
Dries's avatar
 
Dries committed
608 609
  }

Dries's avatar
 
Dries committed
610 611
  if ($type == 'system') {
    menu('node/add', t('create content'), 'node_page', 1, MENU_HIDE_NOCHILD);
Dries's avatar
 
Dries committed
612

Dries's avatar
 
Dries committed
613 614 615 616 617 618
    if (user_access('administer nodes')) {
      menu('admin/node', t('content'), 'node_admin');
      menu('admin/node/search', t('search'), 'node_admin', 8);
      menu('admin/node/help', t('help'), 'node_help_page', 9);
      menu('admin/node/edit', t('edit post'), 'node_admin', 0, MENU_HIDE);
      menu('admin/node/settings', t('settings'), 'node_admin', 8);
Dries's avatar
 
Dries committed
619
    }
Dries's avatar
 
Dries committed
620

Dries's avatar
 
Dries committed
621 622
    if (user_access('access content')) {
      menu('node', t('content'), 'node_page', 0, MENU_HIDE);
Dries's avatar
 
Dries committed
623
    }
Dries's avatar
 
Dries committed
624 625
  }

Dries's avatar
 
Dries committed
626
  return $links;
Dries's avatar
 
Dries committed
627 628
}

Dries's avatar
 
Dries committed
629
function node_admin_edit($node) {
Dries's avatar
 
Dries committed
630

Dries's avatar
 
Dries committed
631
  if (is_numeric($node)) {
Dries's avatar
 
Dries committed
632
    $node = node_load(array('nid' => $node));
Dries's avatar
 
Dries committed
633
  }
Dries's avatar
 
Dries committed
634

Dries's avatar
 
Dries committed
635
  $output .= node_form($node);
Dries's avatar
 
Dries committed
636

Dries's avatar
 
Dries committed
637
  /*
Dries's avatar
 
Dries committed
638
  ** Display the node form extensions:
Dries's avatar
 
Dries committed
639
  */
640
  $output .= implode("\n", module_invoke_all('node_link', $node));
Dries's avatar
Dries committed
641

Dries's avatar
 
Dries committed
642
  return $output;
Dries's avatar
 
Dries committed
643 644 645

}

Dries's avatar
 
Dries committed
646
function node_admin_nodes() {
Dries's avatar
 
Dries committed
647
  $filters = array(
Dries's avatar
 
Dries committed
648 649 650 651 652 653
    array(t('View posts that are new or updated'), 'ORDER BY n.changed DESC'),
    array(t('View posts that need approval'), 'WHERE n.status = 0 OR n.moderate = 1 ORDER BY n.changed DESC'),
    array(t('View posts that are promoted'), 'WHERE n.status = 1 AND n.promote = 1 ORDER BY n.changed DESC'),
    array(t('View posts that are not promoted'), 'WHERE n.status = 1 AND n.promote = 0 ORDER BY n.changed DESC'),
    array(t('View posts that are static'), 'WHERE n.status = 1 AND n.static = 1 ORDER BY n.changed DESC'),
    array(t('View posts that are unpublished'), 'WHERE n.status = 0 AND n.moderate = 0 ORDER BY n.changed DESC')
Dries's avatar
 
Dries committed
654 655 656
   );

  $operations = array(
Dries's avatar
 
Dries committed
657 658 659 660 661
    array(t('Approve the selected posts'), 'UPDATE {node} SET status = 1, moderate = 0 WHERE nid = %d'),
    array(t('Promote the selected posts'), 'UPDATE {node} SET status = 1, promote = 1 WHERE nid = %d'),
    array(t('Make the selected posts static'), 'UPDATE {node} SET status = 1, static = 1 WHERE nid = %d'),
    array(t('Demote the selected posts'), 'UPDATE {node} SET promote = 0 WHERE nid = %d'),
    array(t('Unpublish the selected posts'), 'UPDATE {node} SET status = 0 WHERE nid = %d')
Dries's avatar
 
Dries committed
662
  );
Dries's avatar
 
Dries committed
663

Dries's avatar
 
Dries committed
664 665 666 667
  /*
  ** Handle operations:
  */

Dries's avatar
 
Dries committed
668 669
  if (empty($_SESSION['node_overview_filter'])) {
    $_SESSION['node_overview_filter'] = 0;
Dries's avatar
 
Dries committed
670 671
  }

Dries's avatar
 
Dries committed
672 673
  if (isset($_POST['edit']['filter'])) {
    $_SESSION['node_overview_filter'] = $_POST['edit']['filter'];
Dries's avatar
 
Dries committed
674 675
  }

Dries's avatar
 
Dries committed
676 677 678
  if (isset($_POST['edit']['operation'])) {
    $operation = $operations[$_POST['edit']['operation']][1];
    foreach ($_POST['edit']['status'] as $nid => $value) {
Dries's avatar
 
Dries committed
679
      if ($value) {
Dries's avatar
Dries committed
680
        db_query($operation, $nid);
Dries's avatar
 
Dries committed
681 682 683
      }
    }

Dries's avatar
 
Dries committed
684
    drupal_set_message(t('the update has been performed.'));
Dries's avatar
 
Dries committed
685 686
  }

Dries's avatar
 
Dries committed
687
  $filter = $_SESSION['node_overview_filter'];
Dries's avatar
Dries committed
688

Dries's avatar
 
Dries committed
689 690 691 692 693 694 695 696
  /*
  ** Render filter form:
  */

  $options = array();
  foreach ($filters as $key => $value) {
    $options[] = $value[0];
  }
Dries's avatar
 
Dries committed
697

Dries's avatar
 
Dries committed
698 699
  $form  = form_select(NULL, 'filter', $filter, $options);
  $form .= form_submit(t('Go'));
Dries's avatar
 
Dries committed
700

Dries's avatar
 
Dries committed
701
  $output .= '<h3>'. t('Filter options') .'</h3>';
Dries's avatar
 
Dries committed
702 703 704 705 706 707 708 709 710 711 712
  $output .= "<div class=\"container-inline\">$form</div>";

  /*
  ** Render operations form:
  */

  $options = array();
  foreach ($operations as $key => $value) {
    $options[] = $value[0];
  }

Dries's avatar
 
Dries committed
713 714
  $form = form_select(NULL, 'operation', 0, $options);
  $form .= form_submit(t('Go'));
Dries's avatar
 
Dries committed
715

Dries's avatar
 
Dries committed
716
  $output .= '<h3>'. t('Update options') .'</h3>';
Dries's avatar
 
Dries committed
717 718 719 720 721 722
  $output .= "<div class=\"container-inline\">$form</div>";

  /*
  ** Overview table:
  */

Dries's avatar
 
Dries committed
723 724
  $result = pager_query('SELECT n.*, u.name, u.uid FROM {node} n INNER JOIN {users} u ON n.uid = u.uid '. $filters[$filter][1], 50);
  $header = array(NULL, t('title'), t('type'), t('author'), t('status'), array('data' => t('operations'), 'colspan' => 2));
Dries's avatar
 
Dries committed
725

Dries's avatar
 
Dries committed
726
  while ($node = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
727
    $rows[] = array(form_checkbox(NULL, "status][$node->nid", 1, 0), l($node->title, "node/view/$node->nid") .' '. (node_is_new($node->nid, $node->changed) ? theme_mark() : ''), node_invoke($node, 'node_name'), format_name($node), ($node->status ? t('published') : t('not published')), l(t('edit node'), "admin/node/edit/$node->nid"), l(t('delete node'), "admin/node/delete/$node->nid"));
Dries's avatar
 
Dries committed
728
  }
Dries's avatar
 
Dries committed
729

Dries's avatar
 
Dries committed
730 731
  if ($pager = theme('pager', NULL, 50, 0)) {
    $rows[] = array(array('data' => $pager, 'colspan' => 7));
Dries's avatar
 
Dries committed
732
  }
Dries's avatar
 
Dries committed
733

Dries's avatar
 
Dries committed
734 735
  $output .= '<h3>'. $filters[$filter][0] .'</h3>';
  $output .= theme('table', $header, $rows);
Dries's avatar
 
Dries committed
736
  return form($output);
Dries's avatar
Dries committed
737 738
}

739
function node_admin_settings($edit) {
Dries's avatar
 
Dries committed
740
  $op = $_POST['op'];
Kjartan's avatar
Kjartan committed
741

Dries's avatar
 
Dries committed
742
  if ($op == t('Save configuration')) {
743 744 745 746 747 748 749
    /*
    ** Save the configuration options:
    */

    foreach ($edit as $name => $value) {
      variable_set($name, $value);
    }
Dries's avatar
 
Dries committed
750
    drupal_set_message(t('the content settings have been saved.'));
751 752
  }

Dries's avatar
 
Dries committed
753
  if ($op == t('Reset to defaults')) {
754 755 756 757 758 759 760
    /*
    ** Reset the configuration options to their default value:
    */

    foreach ($edit as $name => $value) {
      variable_del($name);
    }
Dries's avatar
 
Dries committed
761
    drupal_set_message(t('the content settings have been reset to their default values.'));
762 763
  }

Dries's avatar
 
Dries committed
764
  $header = array_merge(array(t('type')), array_keys(node_invoke_nodeapi($node, 'settings')));
Dries's avatar
 
Dries committed
765
  foreach (node_list() as $type) {
Dries's avatar
 
Dries committed
766 767
    $node->type = $type;
    $cols = array();
Dries's avatar
 
Dries committed
768 769
    foreach (node_invoke_nodeapi($node, 'settings') as $setting) {
      $cols[] = array('data' => $setting, 'align' => 'center', 'width' => 55);
770
    }
Dries's avatar
 
Dries committed
771
    $rows[] = array_merge(array(node_invoke($node, 'node_name')), $cols);
772
  }
Kjartan's avatar
Kjartan committed
773

Dries's avatar
 
Dries committed
774
  $output .= theme('table', $header, $rows);
775

776
  /* This is an idea for the future.
Dries's avatar
 
Dries committed
777
  foreach (node_list() as $type) {
Dries's avatar
 
Dries committed
778
    $node->type = $type;
Kjartan's avatar
Kjartan committed
779

Dries's avatar
 
Dries committed
780 781
      // Create theme('table', ) data:
      $header = array_keys(node_invoke_nodeapi($node, 'settings'));
782
      $cols = array();
Dries's avatar
 
Dries committed
783 784
      foreach (node_invoke_nodeapi($node, 'settings') as $setting) {
        $cols[] = array('data' => $setting, 'align' => 'center', 'width' => 75);
785 786
      }

Dries's avatar
 
Dries committed
787 788 789
      $output .= '<h2>'. node_invoke($node, 'node_name') .'</h2>';
      $output .= theme('table', $header, array($cols));
      $output .= '<br /><br />';
790 791
    }
  }
792
  */
793

Dries's avatar
 
Dries committed
794 795
  $output .= form_submit(t('Save configuration'));
  $output .= form_submit(t('Reset to defaults'));
Kjartan's avatar
Kjartan committed
796

Dries's avatar
 
Dries committed
797
  return form($output);
798 799 800

}

Dries's avatar
 
Dries committed
801 802
function node_revision_overview($nid) {

Dries's avatar
 
Dries committed
803 804
  if (user_access('administer nodes')) {
    $node = node_load(array('nid' => $nid));
Dries's avatar
 
Dries committed
805 806

    if ($node->revisions) {
Dries's avatar
 
Dries committed
807
      $header = array(t('older revisions'), array('colspan' => '3', 'data' => t('operations')));
Dries's avatar
 
Dries committed
808 809

      foreach ($node->revisions as $key => $revision) {
Dries's avatar
 
Dries committed
810
        $rows[] = array(t('revision #%r revised by %u on %d', array('%r' => $key, '%u' => format_name(user_load(array('uid' => $revision['uid']))), '%d' => format_date($revision['timestamp'], 'small'))) . ($revision['history'] ? '<br /><small>'. $revision['history'] .'</small>' : ''), l(t('view'), "node/view/$node->nid", array(), "revision=$key"), l(t('rollback'), "node/rollback-revision/$node->nid/$key"), l(t('delete'), "node/delete-revision/$node->nid/$key"));
Dries's avatar
 
Dries committed
811
      }
Dries's avatar
 
Dries committed
812
      $output .= theme('table', $header, $rows);
Dries's avatar
 
Dries committed
813 814 815 816 817 818 819
    }
  }

  return $output;
}


Dries's avatar
 
Dries committed
820 821 822 823 824
/*
** Return the revision with the specified revision number.
*/

function node_revision_load($node, $revision) {
Dries's avatar
 
Dries committed
825
  return $node->revisions[$revision]['node'];
Dries's avatar
 
Dries committed
826 827 828 829 830 831
}

/*
** Create and return a new revision of the given node.
*/

Dries's avatar
 
Dries committed
832 833 834
function node_revision_create($node) {
  global $user;

Dries's avatar
 
Dries committed
835 836 837 838 839
  /*
  ** 'revision' is the name of the field used to indicicate that we
  ** have to create a new revision of a node.
  */

Dries's avatar
 
Dries committed
840
  if ($node->nid && $node->revision) {
Dries's avatar
 
Dries committed
841
    $prev = node_load(array('nid' => $node->nid));
Dries's avatar
 
Dries committed
842 843
    $node->revisions = $prev->revisions;
    unset($prev->revisions);
Dries's avatar
 
Dries committed
844
    $node->revisions[] = array('uid' => $user->uid, 'timestamp' => time(), 'node' => $prev, 'history' => $node->history);
Dries's avatar
 
Dries committed
845 846 847 848 849
  }

  return $node;
}

Dries's avatar
 
Dries committed
850 851 852
/*
** Roll-back to the revision with the specified revision number.
*/
Dries's avatar
 
Dries committed
853

Dries's avatar
 
Dries committed
854
function node_revision_rollback($nid, $revision) {
Dries's avatar
 
Dries committed
855
  global $user;
Dries's avatar
 
Dries committed
856

Dries's avatar
 
Dries committed
857 858
  if (user_access('administer nodes')) {
    $node = node_load(array('nid' => $nid));
Dries's avatar
 
Dries committed
859

Dries's avatar
 
Dries committed
860 861 862
    /*
    ** Extract the specified revision:
    */
Dries's avatar
 
Dries committed
863

Dries's avatar
 
Dries committed
864
    $rev = $node->revisions[$revision]['node'];
Dries's avatar
 
Dries committed
865

Dries's avatar
 
Dries committed
866 867 868
    /*
    ** Inherit all the past revisions:
    */
Dries's avatar
 
Dries committed
869

Dries's avatar
 
Dries committed
870
    $rev->revisions = $node->revisions;
Dries's avatar
 
Dries committed
871

Dries's avatar
 
Dries committed
872 873 874
    /*
    ** Save the original/current node:
    */
Dries's avatar
 
Dries committed
875

Dries's avatar
 
Dries committed
876
    $rev->revisions[] = array('uid' => $user->uid, 'timestamp' => time(), 'node' => $node);
Dries's avatar
 
Dries committed
877

Dries's avatar
 
Dries committed
878 879 <