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

Dries's avatar
 
Dries committed
4 5 6 7 8 9
function node_help() {
  global $mod;

  if ($mod == "node") {
    foreach (module_list() as $name) {
      if (module_hook($name, "status") && $name != "node") {
Dries's avatar
 
Dries committed
10
        print "<h3>". ucfirst($name) ." type</h3>";
Dries's avatar
 
Dries committed
11 12 13 14 15 16
        print module_invoke($name, "help");
      }
    }
  }
}

Dries's avatar
 
Dries committed
17
// DEPRICATED: still used by themes, yet doesn't return anything at the moment
Dries's avatar
 
Dries committed
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
function node_index() {
}

function node_teaser($body) {

  $size = 400;

  /*
  ** If we have a short body, return the entire body:
  */

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

  /*
  ** If we have a long body, try not to split paragraphs:
  */

  if ($length = strpos($body, "\n", $size)) {
    return substr($body, 0, $length + 1);
  }

  /*
  ** If we have a long body, try not to split sentences:
  */

  return substr($body, 0, strpos($body, ". ", $size) + 1);

}

function node_invoke($node, $name, $arg = 0) {
  if (is_array($node)) {
    $function = $node[type] ."_$name";
  }
  else if (is_object($node)) {
    $function = $node->type ."_$name";
  }
  else if (is_string($node)) {
    $function = $node ."_$name";
  }

  if (function_exists($function)) {
    return ($arg ? $function($node, $arg) : $function($node));
  }
}

function node_load($conditions) {

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

  foreach ($conditions as $key => $value) {
    $cond[] = "n.". check_query($key) ." = '". check_query($value) ."'";
  }

  /*
  ** Retrieve the node:
  */

  $node = db_fetch_object(db_query("SELECT n.*, u.uid, u.name FROM node n LEFT JOIN users u ON u.uid = n.uid WHERE ". implode(" AND ", $cond)));

  /*
  ** Unserialize the revisions field:
  */

  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:
  */

  if ($extra = module_invoke($node->type, "load", $node)) {
    foreach ($extra as $key => $value) {
      $node->$key = $value;
    }
  }

  return $node;
}

function node_save($node, $filter) {

  $fields = array("nid", "uid", "type", "title", "teaser", "body", "revisions", "score", "status", "comment", "promote", "moderate", "created", "changed", "users", "votes");

  foreach ($filter as $key => $value) {
    /*
    ** Only save those fields specified by the filter.  If the filter
    ** does not specify a default value, use the value of the $node's
    ** corresponding field instead.
    */

    if (is_numeric($key)) {
      if (isset($node->$value)) {
          // The above check is mandatory.
        $edit->$value = $node->$value;
      }
    }
    else {
      if (isset($value)) {
          // The above check is mandatory.
        $edit->$key = $value;
      }
    }
  }

  $node = $edit;

  /*
  ** 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
148
    // Set some required fields:
Dries's avatar
 
Dries committed
149
    $node->created = time();
Dries's avatar
 
Dries committed
150
    $node->changed = time();
Dries's avatar
 
Dries committed
151 152
    $node->nid = db_result(db_query("SELECT MAX(nid) + 1 FROM node"));

Dries's avatar
 
Dries committed
153
    // Prepare the query:
Dries's avatar
 
Dries committed
154 155 156 157 158 159 160
    foreach ($node as $key => $value) {
      if (in_array($key, $fields)) {
        $k[] = check_query($key);
        $v[] = "'". check_query($value) ."'";
      }
    }

Dries's avatar
 
Dries committed
161
    // Insert the node into the database:
Dries's avatar
 
Dries committed
162 163
    db_query("INSERT INTO node (". implode(", ", $k) .") VALUES (". implode(", ", $v) .")");

Dries's avatar
 
Dries committed
164
    // Call the node specific callback (if any):
Dries's avatar
 
Dries committed
165 166 167 168 169 170 171 172
    module_invoke($node->type, "insert", $node);
  }
  else {

    /*
    ** Update an existing node:
    */

Dries's avatar
 
Dries committed
173
    // Set some required fields:
Dries's avatar
 
Dries committed
174 175
    $node->changed = time();

Dries's avatar
 
Dries committed
176
    // Prepare the query:
Dries's avatar
 
Dries committed
177 178 179 180 181 182
    foreach ($node as $key => $value) {
      if (in_array($key, $fields)) {
        $q[] = check_query($key) ." = '". check_query($value) ."'";
      }
    }

Dries's avatar
 
Dries committed
183
    // Update the node in the database:
Dries's avatar
 
Dries committed
184 185
    db_query("UPDATE node SET ". implode(", ", $q) ." WHERE nid = '$node->nid'");

Dries's avatar
 
Dries committed
186
    // Call the node specific callback (if any):
Dries's avatar
 
Dries committed
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    module_invoke($node->type, "update", $node);

  }

  /*
  ** Return the node ID:
  */

  return $node->nid;

}

function node_view($node, $main = 0) {
  global $theme;

Dries's avatar
 
Dries committed
202
  $node = array2object($node);
Dries's avatar
 
Dries committed
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221

  /*
  ** The "view" hook can be implemented to overwrite the default function
  ** to display nodes.
  */

  if (module_hook($node->type, "view")) {
    node_invoke($node, "view", $main);
  }
  else {

    /*
    ** Default behavior:
    */

    $theme->node($node, $main);
  }
}

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

Dries's avatar
 
Dries committed
224 225
  if (user_access("administer nodes")) {
    return 1;
Dries's avatar
 
Dries committed
226
  }
Dries's avatar
 
Dries committed
227
  else {
Dries's avatar
 
Dries committed
228

Dries's avatar
 
Dries committed
229 230 231
    /*
    ** Convert the node to an object if necessary:
    */
Dries's avatar
 
Dries committed
232

Dries's avatar
 
Dries committed
233
    $node = array2object($node);
Dries's avatar
 
Dries committed
234

Dries's avatar
 
Dries committed
235 236 237 238
    /*
    ** Construct a function:
    */

Dries's avatar
 
Dries committed
239 240 241 242 243 244 245 246
    if ($node->type) {
      $type = $node->type;
    }
    else {
      $type = $node;
    }

    $function = $type ."_access";
Dries's avatar
 
Dries committed
247 248 249 250 251 252 253

    if (function_exists($function)) {
      return $function($op, $node);
    }
    else {
      return 0;
    }
Dries's avatar
 
Dries committed
254 255 256
  }
}

Dries's avatar
 
Dries committed
257
function node_perm() {
Dries's avatar
 
Dries committed
258
  return array("administer nodes", "access content", "post content");
Dries's avatar
 
Dries committed
259 260
}

Dries's avatar
 
Dries committed
261
function node_search($keys) {
Dries's avatar
 
Dries committed
262
  global $PHP_SELF;
Dries's avatar
 
Dries committed
263 264 265

  $result = db_query("SELECT n.nid, n.title, n.created, u.uid, u.name FROM node n LEFT JOIN users u ON n.uid = u.uid WHERE n.status = 1 AND (n.title LIKE '%$keys%' OR n.teaser LIKE '%$keys%' OR n.body LIKE '%$keys%') ORDER BY n.created DESC LIMIT 20");
  while ($node = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
266
    $find[$i++] = array("title" => check_output($node->title), "link" => (strstr($PHP_SELF, "admin.php") ? "admin.php?mod=node&type=node&op=edit&id=$node->nid" : "node.php?id=$node->nid"), "user" => $node->name, "date" => $node->created);
Dries's avatar
 
Dries committed
267 268 269 270 271
  }

  return $find;
}

Dries's avatar
 
Dries committed
272
function node_conf_options() {
Dries's avatar
 
Dries committed
273
  $output .= form_select(t("Default number of nodes to display"), "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 nodes to display on the main page."));
Dries's avatar
 
Dries committed
274 275 276
  return $output;
}

Dries's avatar
CHANGES  
Dries committed
277
function node_conf_filters() {
Dries's avatar
 
Dries committed
278
  $output .= form_select(t("Enable HTML tags"), "filter_html", variable_get("filter_html", 0), array("Disabled", "Enabled"), t("Allow HTML and PHP tags in user-contributed content."));
279
  $output .= form_textfield(t("Allowed HTML tags"), "allowed_html", variable_get("allowed_html", "<a> <b> <dd> <dl> <dt> <i> <li> <ol> <u> <ul>"), 64, 255, t("If enabled, optionally specify tags which should not be stripped.  'STYLE' attributes, 'ON' attributes and unclosed tags are always stripped."));
Dries's avatar
 
Dries committed
280
  $output .= "<hr />";
Dries's avatar
 
Dries committed
281
  $output .= form_select(t("Enable link tags"), "filter_link", variable_get("filter_link", 0), array("Disabled", "Enabled"), t("Substitute special [[nodesubject|text]] tags. Your browser will display 'text', and when you click on it your browser will open the node with the subject 'nodesubject'. Please be aware that you'll need to copy the subject of the target node exactly in order to use this feature."));
Dries's avatar
 
Dries committed
282
  $output .= "<hr />";
Dries's avatar
CHANGES  
Dries committed
283 284 285 286 287 288 289 290 291 292 293
  return $output;
}

function node_filter_html($text) {
  $text = eregi_replace("([ \f\r\t\n\'\"])style=[^>]+", "\\1", $text);
  $text = eregi_replace("([ \f\r\t\n\'\"])on[a-z]+=[^>]+", "\\1", $text);
  $text = strip_tags($text, variable_get("allowed_html", ""));
  return $text;
}

function node_filter_link($text) {
Dries's avatar
 
Dries committed
294 295 296 297 298
  $src = array("/\[\[(([^\|]*?)(\|([^\|]*?))?)\]\]/e");  // [link|description]
  $dst = array(format_tag('\\2', '\\4'));                // [link|description]
  return preg_replace($src, $dst, $text);
}

Dries's avatar
 
Dries committed
299
function node_filter_line($text) {
Dries's avatar
 
Dries committed
300

Dries's avatar
 
Dries committed
301
  /*
Dries's avatar
 
Dries committed
302 303 304 305 306 307 308
  ** This "line break filter" will try to get the line breaks right
  ** regardless of the user's input.  Its goal aspires a consistent
  ** mark-up and use of line breaks and paragraphs.
  */

  /*
  ** If HTML mark-up is being used, strip regular line breaks:
Dries's avatar
 
Dries committed
309 310 311
  */

  if (strstr($text, "<br />") || strstr($text, "<p>")) {
Dries's avatar
 
Dries committed
312
    $text = ereg_replace("[\r\n]", "", $text);
Dries's avatar
 
Dries committed
313 314 315 316 317 318 319 320 321
  }

  /*
  ** Replace '<br>', '<br />', '<p>' and '<p />' by '\n':
  */

  $text = eregi_replace("<br>", "\n", $text);
  $text = eregi_replace("<br />", "\n", $text);
  $text = eregi_replace("<p>", "\n", $text);
Dries's avatar
 
Dries committed
322
  $text = eregi_replace("<p />", "\n", $text);
Dries's avatar
 
Dries committed
323 324

  /*
Dries's avatar
 
Dries committed
325
  ** Replace '\r\n' by '\n':
Dries's avatar
 
Dries committed
326 327 328 329 330 331 332 333 334 335 336
  */

  $text = ereg_replace("\r\n", "\n", $text);

  /*
  ** Replace some new line charachters:
  */

  while (strpos($text, "\n\n\n")) {
    $text = ereg_replace("\n\n\n", "\n\n", $text);
  }
Dries's avatar
 
Dries committed
337

Dries's avatar
 
Dries committed
338 339 340 341 342 343 344
  /*
  ** Replace some common "artifacts":
  */

  $list = "blockquote|li|ol|ul|table|th|td|tr|pre";
  $text = preg_replace(array("/\n\s*<([\/])($list)/", "/($list)>\s*\n/"), array("<$1$2", "$1>"), $text);

Dries's avatar
 
Dries committed
345 346 347
  return trim($text);
}

Dries's avatar
CHANGES  
Dries committed
348 349 350
function node_filter($text) {
  if (variable_get("filter_html", 0)) $text = node_filter_html($text);
  if (variable_get("filter_link", 0)) $text = node_filter_link($text);
Dries's avatar
 
Dries committed
351
  return node_filter_line($text);
Dries's avatar
CHANGES  
Dries committed
352 353
}

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

Dries's avatar
 
Dries committed
356
  if ($type == "admin" && user_access("administer nodes")) {
Dries's avatar
 
Dries committed
357 358 359
    $links[] = "<a href=\"admin.php?mod=node\">content management</a>";
  }

Dries's avatar
 
Dries committed
360
  if ($type == "page" && user_access("post content")) {
Dries's avatar
 
Dries committed
361
    $links[] = "<a href=\"module.php?mod=node&op=add\" title=\"". t("Submit or suggest new content.") ."\">". t("submit") ."</a>";
Dries's avatar
 
Dries committed
362 363
  }

Dries's avatar
 
Dries committed
364
  if ($type == "node") {
Kjartan's avatar
Kjartan committed
365 366 367
    if ($node->links) {
      $links = $node->links;
    }
Dries's avatar
 
Dries committed
368

Dries's avatar
 
Dries committed
369
    if ($main == 1 && $node->teaser != $node->body) {
Dries's avatar
 
Dries committed
370
      $links[] = "<a href=\"node.php?id=$node->nid\" title=\"". t("Read the rest of this posting.") ."\">". t("read more") ."</a>";
Dries's avatar
 
Dries committed
371
    }
Dries's avatar
 
Dries committed
372 373

    if (user_access("administer nodes")) {
Dries's avatar
 
Dries committed
374
       $links[] = "<a href=\"admin.php?mod=node&op=edit&id=$node->nid\" title=\"". t("Administer this node.") ."\">". t("administer") ."</a>";
Dries's avatar
 
Dries committed
375
    }
Dries's avatar
 
Dries committed
376 377 378 379 380
  }

  return $links ? $links : array();
}

Dries's avatar
 
Dries committed
381
function node_admin_settings($edit = array()) {
Dries's avatar
 
Dries committed
382 383
  global $op;

Dries's avatar
 
Dries committed
384 385 386 387
  if ($op == t("Save configuration")) {
    /*
    ** Save the configuration options:
    */
Dries's avatar
Dries committed
388

Dries's avatar
 
Dries committed
389 390 391
    foreach ($edit as $name => $value) {
      variable_set($name, $value);
    }
Dries's avatar
 
Dries committed
392 393
  }

Dries's avatar
 
Dries committed
394 395 396 397
  if ($op == t("Reset to defaults")) {
    /*
    ** Reset the configuration options to their default value:
    */
Dries's avatar
 
Dries committed
398

Dries's avatar
 
Dries committed
399 400 401
    foreach ($edit as $name=>$value) {
      variable_del($name);
    }
Dries's avatar
 
Dries committed
402
  }
Dries's avatar
Dries committed
403

Dries's avatar
 
Dries committed
404
  $output .= "<h3>". t("Global node settings") ."</h3>";
Dries's avatar
 
Dries committed
405
  $output .= node_conf_options();
Dries's avatar
 
Dries committed
406 407 408

  foreach (module_list() as $name) {
    if (module_hook($name, "conf_options") && module_hook($name, "node")) {
Dries's avatar
 
Dries committed
409
      $output .= "<h3>". ucfirst(module_invoke($name, "node", "name") ." settings") ."</h3>";
Dries's avatar
 
Dries committed
410 411 412 413
      $output .= module_invoke($name, "conf_options");
    }
  }

Dries's avatar
 
Dries committed
414 415
  $output .= form_submit(t("Save configuration"));
  $output .= form_submit(t("Reset to defaults"));
Dries's avatar
Dries committed
416

Dries's avatar
 
Dries committed
417
  return form($output);
Dries's avatar
 
Dries committed
418 419
}

Dries's avatar
 
Dries committed
420
function node_admin_edit($node) {
Dries's avatar
 
Dries committed
421

Dries's avatar
 
Dries committed
422
  if (is_numeric($node)) {
Dries's avatar
 
Dries committed
423
    $node = node_load(array("nid" => $node));
Dries's avatar
 
Dries committed
424
  }
Dries's avatar
 
Dries committed
425

Dries's avatar
 
Dries committed
426 427 428
  /*
  ** Edit node:
  */
Dries's avatar
 
Dries committed
429

Dries's avatar
 
Dries committed
430
  $output .= "<h3>". t("Edit") ." ". module_invoke($node->type, "node", "name") ."</h3>";
Dries's avatar
 
Dries committed
431

Dries's avatar
 
Dries committed
432
  $output .= node_form($node);
Dries's avatar
 
Dries committed
433

Dries's avatar
 
Dries committed
434 435 436 437 438 439 440 441 442
  /*
  ** Edit revisions:
  */

  if ($node->revisions) {
    $output .= "<h3>". t("Edit revisions") ."</h3>";
    $output .= "<table border=\"1\" cellpadding=\"2\" cellspacing=\"2\">";
    $output .= " <tr><th>older revisions</th><th colspan=\"3\">operations</th></tr>";
    foreach ($node->revisions as $key => $revision) {
Dries's avatar
 
Dries committed
443
      $output .= " <tr><td>". sprintf(t("revision #%d revised by %s on %s"), $key, format_name(user_load(array("uid" => $revision["uid"]))), format_date($revision["timestamp"], "small")) . ($revision["history"] ? "<br /><small>". $revision["history"] ."</small>" : "") ."</td><td><a href=\"node.php?id=$node->nid&revision=$key\">". t("view revision") ."</a></td><td><a href=\"admin.php?mod=node&op=rollback+revision&id=$node->nid&revision=$key\">". t("rollback revision") ."</a></td><td><a href=\"admin.php?mod=node&op=delete+revision&id=$node->nid&revision=$key\">". t("delete revision") ."</a></td></tr>";
Dries's avatar
 
Dries committed
444 445 446 447
    }
    $output .= "</table>";
  }

Dries's avatar
 
Dries committed
448
  /*
Dries's avatar
 
Dries committed
449
  ** Display the node form extensions:
Dries's avatar
 
Dries committed
450
  */
Dries's avatar
 
Dries committed
451

Dries's avatar
 
Dries committed
452 453
  foreach (module_list() as $name) {
    $output .= module_invoke($name, "node_link", $node);
Dries's avatar
Dries committed
454 455
  }

Dries's avatar
 
Dries committed
456
  return $output;
Dries's avatar
 
Dries committed
457 458 459

}

Dries's avatar
 
Dries committed
460 461
function node_admin_nodes() {
  global $query;
Dries's avatar
 
Dries committed
462

Dries's avatar
 
Dries committed
463
  $queries = array(array("ORDER BY n.created DESC", "new nodes"), array("ORDER BY n.changed DESC", "updated nodes"), array("WHERE n.status = 1 AND n.moderate = 0 ORDER BY n.nid DESC", "published nodes"), array("WHERE n.status = 0 AND n.moderate = 0 ORDER BY n.nid DESC", "non-published nodes"), array("WHERE n.status = 1 AND n.moderate = 1 ORDER BY n.nid DESC", "pending nodes"), array("WHERE n.status = 1 AND n.promote = 1 ORDER BY n.nid DESC", "promoted nodes"));
Dries's avatar
 
Dries committed
464

Dries's avatar
 
Dries committed
465
  $result = db_query("SELECT n.*, u.name, u.uid FROM node n LEFT JOIN users u ON n.uid = u.uid ". $queries[$query ? $query : 1][0] ." LIMIT 50");
Dries's avatar
 
Dries committed
466

Dries's avatar
 
Dries committed
467 468
  foreach ($queries as $key => $value) {
    $links[] = "<a href=\"admin.php?mod=node&op=nodes&query=$key\">$value[1]</a>";
Dries's avatar
Dries committed
469 470
  }

Dries's avatar
 
Dries committed
471
  $output .= "<small>". implode(" :: ", $links) ."</small><hr />";
Dries's avatar
 
Dries committed
472

Dries's avatar
 
Dries committed
473 474 475
  $output .= "<table border=\"1\" cellpadding=\"2\" cellspacing=\"2\">\n";
  $output .= " <tr><th>title</th><th>type</th><th>author</th><th>status</th><th colspan=\"2\">operations</th></tr>\n";
  while ($node = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
476
    $output .= "<tr><td><a href=\"node.php?id=$node->nid\">". check_output($node->title) ."</a></td><td>$node->type</td><td nowrap=\"nowrap\">". format_name($node) ."</td><td>". ($node->status ? t("published") : t("not published")) ."</td><td nowrap=\"nowrap\"><a href=\"admin.php?mod=node&op=edit&id=$node->nid\">". t("edit node") ."</a></td><td nowrap=\"nowrap\"><a href=\"admin.php?mod=node&op=delete&id=$node->nid\">". t("delete node") ."</a></td></tr>";
Dries's avatar
 
Dries committed
477
  }
Dries's avatar
 
Dries committed
478
  $output .= "</table>";
Dries's avatar
 
Dries committed
479

Dries's avatar
 
Dries committed
480
  return $output;
Dries's avatar
Dries committed
481 482
}

Dries's avatar
 
Dries committed
483 484 485 486 487 488 489 490 491 492 493 494
/*
** Return the revision with the specified revision number.
*/

function node_revision_load($node, $revision) {
  return $node->revisions[$revision]["node"];
}

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

Dries's avatar
 
Dries committed
495 496 497
function node_revision_create($node) {
  global $user;

Dries's avatar
 
Dries committed
498 499 500 501 502
  /*
  ** '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
503
  if ($node->nid && $node->revision) {
Dries's avatar
 
Dries committed
504 505 506 507
    $prev = node_load(array("nid" => $node->nid));
    $node->revisions = $prev->revisions;
    unset($prev->revisions);
    $node->revisions[] = array("uid" => $user->uid, "timestamp" => time(), "node" => $prev, "history" => $node->history);
Dries's avatar
 
Dries committed
508 509 510 511 512
  }

  return $node;
}

Dries's avatar
 
Dries committed
513 514 515
/*
** Roll-back to the revision with the specified revision number.
*/
Dries's avatar
 
Dries committed
516

Dries's avatar
 
Dries committed
517 518
function node_revision_rollback($node, $revision) {
  global $user;
Dries's avatar
 
Dries committed
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553

  /*
  ** Extract the specified revision:
  */

  $rev = $node->revisions[$revision]["node"];

  /*
  ** Inherit all the past revisions:
  */

  $rev->revisions = $node->revisions;

  /*
  ** Save the original/current node:
  */

  $rev->revisions[] = array("uid" => $user->uid, "timestamp" => time(), "node" => $node);

  /*
  ** Remove the specified revision:
  */

  unset($rev->revisions[$revision]);

  /*
  ** Save the node:
  */

  foreach ($node as $key => $value) {
    $filter[] = $key;
  }

  node_save($rev, $filter);

Dries's avatar
 
Dries committed
554
  watchdog("special", "$node->type: rollbacked to revision #$revision of '$node->title'");
Dries's avatar
 
Dries committed
555 556
}

Dries's avatar
 
Dries committed
557 558 559 560 561
/*
** Delete the revision with specified revision number.
*/

function node_revision_delete($node, $revision) {
Dries's avatar
 
Dries committed
562 563

  unset($node->revisions[$revision]);
Dries's avatar
 
Dries committed
564

Dries's avatar
 
Dries committed
565
  node_save($node, array("nid", "revisions"));
Dries's avatar
 
Dries committed
566

Dries's avatar
 
Dries committed
567
  watchdog("special", "$node->type: removed revision #$revision of '$node->title'");
Dries's avatar
 
Dries committed
568 569
}

Dries's avatar
 
Dries committed
570 571 572 573 574 575 576 577 578 579 580
/*
** Return a list of all the existing revision numbers.
*/

function node_revision_list($node) {
  if (is_array($node->revisions)) {
    return array_keys($node->revisions);
  }
  else {
    return array();
  }
Dries's avatar
 
Dries committed
581 582
}

Dries's avatar
 
Dries committed
583
function node_admin() {
Dries's avatar
 
Dries committed
584
  global $op, $id, $revision, $edit;
Dries's avatar
 
Dries committed
585

Dries's avatar
 
Dries committed
586
  if (user_access("administer nodes")) {
Dries's avatar
 
Dries committed
587

Dries's avatar
 
Dries committed
588 589 590
    /*
    ** Compile a list of the administrative links:
    */
Dries's avatar
Dries committed
591

Dries's avatar
 
Dries committed
592 593 594 595
    $links[] = "<a href=\"admin.php?mod=node&op=nodes\">nodes</a>";
    $links[] = "<a href=\"admin.php?mod=node&op=search\">search content</a>";
    $links[] = "<a href=\"admin.php?mod=node&op=settings\">settings</a>";
    $links[] = "<a href=\"admin.php?mod=node&op=help\">help</a>";
Dries's avatar
 
Dries committed
596

Dries's avatar
 
Dries committed
597
    print "<small>". implode(" &middot; ", $links) ."</small><hr />";
Dries's avatar
 
Dries committed
598 599 600 601 602 603

    switch ($op) {
      case "help":
        print node_help();
        break;
      case "search":
Dries's avatar
 
Dries committed
604
        print search_type("node", "admin.php?mod=node&op=search");
Dries's avatar
 
Dries committed
605
        break;
Dries's avatar
 
Dries committed
606 607 608 609
      case t("Save configuration"):
      case t("Reset to defaults"):
      case "settings":
        print node_admin_settings($edit);
Dries's avatar
 
Dries committed
610 611
        break;
      case "edit":
Dries's avatar
 
Dries committed
612
        print node_admin_edit($id);
Dries's avatar
 
Dries committed
613
        break;
Dries's avatar
 
Dries committed
614 615 616
      case "delete":
        print node_delete(array("nid" => $id));
        break;
Dries's avatar
 
Dries committed
617
      case "rollback revision":
Dries's avatar
 
Dries committed
618 619
        print node_revision_rollback(node_load(array("nid" => $id)), $revision);
        print node_admin_edit($id);
Dries's avatar
 
Dries committed
620 621
        break;
      case "delete revision":
Dries's avatar
 
Dries committed
622 623
        print node_revision_delete(node_load(array("nid" => $id)), $revision);
        print node_admin_edit($id);
Dries's avatar
 
Dries committed
624
        break;
Dries's avatar
 
Dries committed
625
      case t("Preview"):
Dries's avatar
 
Dries committed
626
        print node_preview($edit);
Dries's avatar
 
Dries committed
627
        break;
Dries's avatar
 
Dries committed
628
      case t("Submit"):
Dries's avatar
 
Dries committed
629 630 631
        print node_submit($edit);
        break;
      case t("Delete"):
Dries's avatar
 
Dries committed
632
        print node_delete($edit);
Dries's avatar
 
Dries committed
633
        break;
Dries's avatar
 
Dries committed
634
      default:
Dries's avatar
 
Dries committed
635
        print node_admin_nodes();
Dries's avatar
 
Dries committed
636 637 638 639
    }
  }
  else {
    print message_access();
Dries's avatar
 
Dries committed
640 641 642
  }
}

Dries's avatar
 
Dries committed
643 644 645 646
function node_block() {
  global $theme;

  $block[0][subject] = t("Syndicate");
Dries's avatar
 
Dries committed
647
  $block[0][content] = "<div align=\"center\"><a href=\"module.php?mod=node&op=feed\" title=\"". t("Read the XML version of this page.")."\"><img src=\"". $theme->image("xml.gif") ."\" width=\"36\" height=\"14\" border=\"0\" alt=\"XML\" /></a></div>\n";
Dries's avatar
 
Dries committed
648 649 650 651 652 653
  $block[0][info] = "Syndicate";

  return $block;
}

function node_feed() {
Dries's avatar
 
Dries committed
654

Dries's avatar
 
Dries committed
655
  $result = db_query("SELECT nid, type FROM node WHERE promote = '1' AND status = '1' ORDER BY created DESC LIMIT 15");
Dries's avatar
 
Dries committed
656 657

  while ($node = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
658
    $item = node_load(array("nid" => $node->nid, "type" => $node->type));
Dries's avatar
 
Dries committed
659 660 661

    $link = path_uri() ."node.php?id=$item->nid";

Dries's avatar
 
Dries committed
662
    $items .= format_rss_item($item->title, $link, $item->teaser);
Dries's avatar
 
Dries committed
663 664 665
  }

  $output .= "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
Dries's avatar
 
Dries committed
666
  // $output .= "<!DOCTYPE rss [<!ENTITY % HTMLlat1 PUBLIC \"-//W3C//ENTITIES Latin 1 for XHTML//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent\">\n";
Dries's avatar
 
Dries committed
667
  $output .= "<rss version=\"0.91\">\n";
Dries's avatar
 
Dries committed
668
  $output .= format_rss_channel(variable_get("site_name", "drupal") ." - ". variable_get("site_slogan", ""), path_uri(), variable_get("site_mission", ""), $items);
Dries's avatar
 
Dries committed
669 670
  $output .= "</rss>\n";

Dries's avatar
 
Dries committed
671 672
  header("Content-Type: text/xml");

Dries's avatar
 
Dries committed
673 674 675 676
  print $output;

}

Dries's avatar
 
Dries committed
677

678
function node_validate($node, &$error) {
Dries's avatar
 
Dries committed
679 680 681 682 683 684 685

  global $user;

  /*
  ** Convert the node to an object if necessary:
  */

Dries's avatar
 
Dries committed
686
  $node = array2object($node);
Dries's avatar
 
Dries committed
687 688 689 690 691

  /*
  ** Validate the title field:
  */

Dries's avatar
 
Dries committed
692
  if (isset($node->title) && !$node->title) {
Dries's avatar
 
Dries committed
693 694 695 696 697 698 699 700 701
    $error["title"] = "<div style=\"color: red;\">". t("You have to specify a valid title.") ."</div>";
  }

  if (user_access("administer nodes")) {

    /*
    ** Setup default values if required:
    */

Dries's avatar
 
Dries committed
702 703
    if (!$node->created) {
      $node->created = time();
Dries's avatar
 
Dries committed
704 705
    }

Dries's avatar
 
Dries committed
706 707
    if (!$node->date) {
      $node->date = date("M j, Y g:i a", $node->created);
Dries's avatar
 
Dries committed
708 709 710 711 712 713
    }

    /*
    ** Validate the "authored by"-field:
    */

Dries's avatar
 
Dries committed
714 715 716 717 718 719 720 721 722
    if (empty($node->name)) {
      /*
      ** The use of empty() is mandatory in the context of usernames
      ** as the empty string denotes the anonymous user.  In case we
      ** are dealing with an anomymous user we set the user ID to 0.
      */
      $node->uid = 0;
    }
    else if ($account = user_load(array("name" => $node->name))) {
Dries's avatar
 
Dries committed
723
      $node->uid = $account->uid;
Dries's avatar
 
Dries committed
724 725
    }
    else {
Dries's avatar
 
Dries committed
726
      $error["name"] = "<div style=\"color: red;\">". sprintf(t("The name '%s' does not exist."), $node->name) ."</div>";
Dries's avatar
 
Dries committed
727 728 729 730 731 732
    }

    /*
    ** Validate the "authored on"-field:
    */

Dries's avatar
 
Dries committed
733 734
    if (strtotime($node->date) > 1000) {
      $node->created = strtotime($node->date);
Dries's avatar
 
Dries committed
735 736 737 738
    }
    else {
      $error["date"] = "<div style=\"color: red;\">". t("You have to specifiy a valid date.") ."</div>";
    }
Dries's avatar
 
Dries committed
739

Dries's avatar
 
Dries committed
740 741
  }

Dries's avatar
 
Dries committed
742
  return $node;
Dries's avatar
 
Dries committed
743 744
}

Dries's avatar
 
Dries committed
745

Dries's avatar
 
Dries committed
746 747
function node_form($edit) {

Dries's avatar
 
Dries committed
748 749 750 751 752 753 754
  /*
  ** Save the referer.  We record where the user came from such that we
  ** can redirect him after having completed the node forms.
  */

  referer_save();

Dries's avatar
 
Dries committed
755 756 757 758
  /*
  ** Validate the node:
  */

759
  $edit = node_validate($edit, $error);
Dries's avatar
 
Dries committed
760

Dries's avatar
 
Dries committed
761 762 763 764 765 766 767 768
  /*
  ** Generate a teaser when necessary:
  */

  if ($edit->body && !$edit->teaser) {
    $edit->teaser = node_teaser($edit->body);
  }

Dries's avatar
 
Dries committed
769 770 771 772 773 774
  /*
  ** Get the node specific bits:
  */

  $function = $edit->type ."_form";
  if (function_exists($function)) {
775
    $form .= $function($edit, $help, $error);
Dries's avatar
 
Dries committed
776 777 778 779 780 781 782 783 784 785
  }

  /*
  ** Add the help text:
  */

  if ($help) {
    $output .= "<p>$help</p>";
  }

Dries's avatar
 
Dries committed
786 787 788 789
  $output .= "<table border=\"0\" cellpadding=\"2\" cellspacing=\"2\">";
  $output .= " <tr>";
  $output .= "  <td valign=\"top\">";

Dries's avatar
 
Dries committed
790 791 792 793 794 795 796
  /*
  ** Add the default fields:
  */

  $output .= form_textfield(t("Title"), "title", $edit->title, 60, 64, $error["title"]);

  /*
Dries's avatar
 
Dries committed
797
  ** Add the node specific fields:
Dries's avatar
 
Dries committed
798 799
  */

Dries's avatar
 
Dries committed
800
  $output .= $form;
Dries's avatar
 
Dries committed
801 802 803 804 805 806 807 808 809

  /*
  ** Add the hidden fields:
  */

  if ($edit->nid) {
    $output .= form_hidden("nid", $edit->nid);
  }

Dries's avatar
 
Dries committed
810 811 812 813 814
  if (isset($edit->uid)) {
      /*
      ** The use of isset() is mandatory in the context of user IDs as uid
      ** 0 denotes the anonymous user.
      */
Dries's avatar
 
Dries committed
815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
    $output .= form_hidden("uid", $edit->uid);
  }

  if ($edit->created) {
    $output .= form_hidden("created", $edit->created);
  }

  $output .= form_hidden("type", $edit->type);

  /*
  ** Add the buttons:
  */

  $output .= form_submit(t("Preview"));

  if ($edit->title && $edit->type && !$error) {
    $output .= form_submit(t("Submit"));
  }

Dries's avatar
 
Dries committed
834
  if ($edit->nid && node_access("delete", $edit)) {
Dries's avatar
 
Dries committed
835 836 837 838 839 840 841 842
    $output .= form_submit(t("Delete"));
  }

  /*
  ** Add the admin specific parts:
  */

  if (user_access("administer nodes")) {
Dries's avatar
 
Dries committed
843
    $output .= "</td><td align=\"left\" valign=\"top\">";
Dries's avatar
 
Dries committed
844

Dries's avatar
 
Dries committed
845 846 847
    $output .= form_textfield(t("Authored by"), "name", $edit->name, 20, 25, $error["name"]);
    $output .= form_textfield(t("Authored on"), "date", $edit->date, 20, 25, $error["date"]);
    $output .= "<br />";
Dries's avatar
 
Dries committed
848
    $output .= form_select(t("Set public/published"), "status", $edit->status, array("Disabled", "Enabled"));
Dries's avatar
 
Dries committed
849
    $output .= form_select(t("Queue for moderation"), "moderate", $edit->moderate, array("Disabled", "Enabled"));
Dries's avatar
 
Dries committed
850
    $output .= form_select(t("Promote to front page"), "promote", $edit->promote, array("Disabled", "Enabled"));
Dries's avatar
 
Dries committed
851
    $output .= form_select(t("Allow users comments"), "comment", $edit->comment, array("Disabled", "Enabled"));
Dries's avatar
 
Dries committed
852
    $output .= form_select(t("Create new revision"), "revision", $edit->revision, array("Disabled", "Enabled"));
Dries's avatar
 
Dries committed
853 854
  }

Dries's avatar
 
Dries committed
855 856 857 858
  $output .= "  </td>";
  $output .= " </tr>";
  $output .= "</table>";

Dries's avatar
 
Dries committed
859 860 861 862 863 864
  return form($output);
}

function node_add($type) {
  global $user;

Dries's avatar
 
Dries committed
865
  /*
Dries's avatar
 
Dries committed
866
  ** If a node type has been specified, validate it existence.  If no
Dries's avatar
 
Dries committed
867 868 869
  ** (valid) node type has been provied, display a node type overview.
  */

Dries's avatar
 
Dries committed
870
  if ($type && node_access("create", $type)) {
Dries's avatar
 
Dries committed
871
    $output = node_form(array("uid" => $user->uid, "name" => $user->name, "type" => $type));
Dries's avatar
 
Dries committed
872 873
  }
  else {
Dries's avatar
 
Dries committed
874

Dries's avatar
 
Dries committed
875 876 877
    /*
    ** Compile a list with the different node types and their explanation:
    */
Dries's avatar
 
Dries committed
878

Dries's avatar
 
Dries committed
879
    foreach (module_list() as $name) {
Dries's avatar
 
Dries committed
880 881
      if (module_hook($name, "node") && node_access("create", array("type" => $name))) {
        $output .= "<li>";
Dries's avatar
 
Dries committed
882
        $output .= " <a href=\"module.php?mod=node&op=add&type=$name\" title=\"". sprintf(t("Add a new %s."), module_invoke($name, "node", "name")) ."\">". module_invoke($name, "node", "name") ."</a>";
Dries's avatar
 
Dries committed
883 884
        $output .= " <div style=\"margin-left: 20px;\">". module_invoke($name, "node", "description") ."</div>";
        $output .= "</li>";
Dries's avatar
 
Dries committed
885
      }
Dries's avatar
 
Dries committed
886 887
    }

Dries's avatar
 
Dries committed
888 889
    $output = t("Choose the appropriate item from the list:") ."<ul>$output</ul>";

Dries's avatar
 
Dries committed
890 891 892 893 894 895 896 897 898 899
  }

  return $output;
}

function node_edit($id) {
  global $user;

  $node = node_load(array("nid" => $id));

Dries's avatar
 
Dries committed
900 901 902 903 904 905 906 907
  if (node_access("update", $node)) {
    $output = node_form($node);
  }
  else {
    $output = message_access();
  }

  return $output;
Dries's avatar
 
Dries committed
908 909
}

Dries's avatar
 
Dries committed
910 911 912 913 914 915
function node_preview($node) {

  /*
  ** Convert the array to an object:
  */

Dries's avatar
 
Dries committed
916
  $node = array2object($node);
Dries's avatar
 
Dries committed
917 918 919 920 921

  /*
  ** Load the user's name when needed:
  */

Dries's avatar
 
Dries committed
922 923 924 925 926 927 928 929
  if (isset($node->name)) {
    /*
    ** The use of isset() is mandatory in the context of user IDs as uid
    ** 0 denotes the anonymous user.
    */

    if ($user = user_load(array("name" => $node->name))) {
      $node->uid = $user->uid;
Dries's avatar
 
Dries committed
930 931
    }
    else {
Dries's avatar
 
Dries committed
932
      $node->uid = 0; // anonymous user
Dries's avatar
 
Dries committed
933
    }
Dries's avatar
 
Dries committed
934
  }
Dries's avatar
 
Dries committed
935
  else if ($node->uid) {
Dries's avatar
 
Dries committed
936 937
    $user = user_load(array("uid" => $node->uid));
    $node->name = $user->name;
Dries's avatar
 
Dries committed
938 939 940 941 942 943
  }

  /*
  ** Set the created time when needed:
  */

Dries's avatar
 
Dries committed
944 945
  if (empty($node->nid)) {
    $node->created = time();
Dries's avatar
 
Dries committed
946 947
  }

Dries's avatar
 
Dries committed
948 949 950 951
  /*
  ** Apply the required filters:
  */

Dries's avatar
 
Dries committed
952
  if ($node->nid) {
Dries's avatar
 
Dries committed
953
    $view = array_merge($node, module_invoke($node->type, "save", "update", $node));
Dries's avatar
 
Dries committed
954 955
  }
  else {
Dries's avatar
 
Dries committed
956
    $view = array_merge($node, module_invoke($node->type, "save", "create", $node));
Dries's avatar
 
Dries committed
957 958
  }

Dries's avatar
 
Dries committed
959 960 961 962
  /*
  ** Display a preview of the node:
  */

Dries's avatar
 
Dries committed
963
  node_view($view);
Dries's avatar
 
Dries committed
964

Dries's avatar
 
Dries committed
965
  return node_form($node);
Dries's avatar
 
Dries committed
966 967
}

Dries's avatar
 
Dries committed
968
function node_submit($node) {
Dries's avatar
 
Dries committed
969
  global $theme, $user;
Dries's avatar
 
Dries committed
970

Dries's avatar
 
Dries committed
971
  if (user_access("post content")) {
Dries's avatar
 
Dries committed
972

Dries's avatar
 
Dries committed
973 974 975
    /*
    ** Fixup the node when required:
    */
Dries's avatar
 
Dries committed
976

977
    $node = node_validate($node, $error);
Dries's avatar
 
Dries committed
978

Dries's avatar
 
Dries committed
979
    /*
Dries's avatar
 
Dries committed
980
    ** Create a new revision when required:
Dries's avatar
 
Dries committed
981 982
    */

Dries's avatar
 
Dries committed
983 984 985
    $node = node_revision_create($node);

    if ($node->nid) {
Dries's avatar
 
Dries committed
986 987

      /*
Dries's avatar
 
Dries committed
988 989
      ** Check whether the current user has the proper access rights to
      ** perform this operation:
Dries's avatar
 
Dries committed
990 991
      */

Dries's avatar
 
Dries committed
992 993 994 995 996 997 998 999 1000 1001 1002
      if (node_access("update", $node)) {

        /*
        ** Compile a list of the node fields and their default values that users
        ** and administrators are allowed to save when updating a node.
        */

        if (user_access("administer nodes")) {
          $fields = array("nid", "uid", "body", "comment", "created", "promote", "moderate", "revisions", "status", "teaser", "title", "type" => $node->type);
        }
        else {
Dries's avatar
 
Dries committed
1003
          $fields = array("nid", "uid" => ($user->uid ? $user->uid : 0), "body", "teaser", "title", "type" => $node->type);
Dries's avatar
 
Dries committed
1004 1005
        }

Dries's avatar
 
Dries committed
1006
        $nid = node_save($node, array_merge($fields, module_invoke($node->type, "save", "update", $node)));
Dries's avatar
 
Dries committed
1007 1008 1009

        watchdog("special", "$node->type: updated '$node->title'");
        $output = t("The node has been updated.");
Dries's avatar
 
Dries committed
1010 1011
      }
      else {
Dries's avatar
 
Dries committed
1012 1013
        watchdog("warning", "$node->type: not authorized to update node");
        $output = t("You are not authorized to update this node.");
Dries's avatar
 
Dries committed
1014 1015
      }

Dries's avatar
 
Dries committed
1016 1017 1018
    }
    else {

Dries's avatar
 
Dries committed
1019 1020 1021 1022
      /*
      ** Check whether the current user has the proper access rights to
      ** perform this operation:
      */
Dries's avatar
 
Dries committed
1023

Dries's avatar
 
Dries committed
1024
      if (node_access("create", $node)) {
Dries's avatar
 
Dries committed
1025

Dries's avatar
 
Dries committed
1026 1027 1028 1029 1030 1031 1032
        /*
        ** Verify a user's submission rate and avoid duplicate nodes being
        ** inserted:
        */

        throttle("node", variable_get("max_node_rate", 900));

Dries's avatar
 
Dries committed
1033 1034 1035 1036
        /*
        ** Compile a list of the node fields and their default values that users
        ** and administrators are allowed to save when inserting a new node.
        */
Dries's avatar
 
Dries committed
1037

Dries's avatar
 
Dries committed
1038 1039 1040 1041
        if (user_access("administer nodes")) {
          $fields = array("uid", "body", "comment" => 1, "promote", "moderate", "status" => 1, "teaser", "title", "type" => $node->type);
        }
        else {
Dries's avatar
 
Dries committed
1042
          $fields = array("uid" => ($user->uid ? $user->uid : 0), "body", "comment" => 1, "teaser", "title", "type" => $node->type);
Dries's avatar
 
Dries committed
1043 1044
        }

Dries's avatar
 
Dries committed
1045
        $nid = node_save($node, array_merge($fields, module_invoke($node->type, "save", "create", $node)));
Dries's avatar
 
Dries committed
1046

Dries's avatar
 
Dries committed
1047 1048
        watchdog("special", "$node->type: added '$node->title'");
        $output = t("Thanks for your submission.");
Dries's avatar
 
Dries committed
1049 1050
      }
      else {
Dries's avatar
 
Dries committed
1051 1052
        watchdog("warning", "$node->type: not authorized to create node");
        $output = t("You are not authorized to create this node.");
Dries's avatar
 
Dries committed
1053 1054
      }
    }
Dries's avatar
 
Dries committed
1055

Dries's avatar
 
Dries committed
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
    /*
    ** Reload the node from the database:
    */

    $node = node_load(array("nid" => $nid));