node.module 30.8 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 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 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
// TODO: still used by themes, yet doesn't return anything at the moment
function node_index() {
}

function node_get_comments($nid) {
  $comment = db_fetch_object(db_query("SELECT COUNT(c.lid) AS number FROM node n LEFT JOIN comments c ON n.nid = c.lid WHERE n.nid = '$nid' GROUP BY n.nid"));
  return $comment->number ? $comment->number : 0;
}

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_object($node) {

  if (is_array($node)) {
    foreach ($node as $key => $value) {
      $object->$key = $value;
    }
  }
  else {
    $object = $node;
  }

  return $object;
}

function node_array($node) {

  if (is_object($node)) {
    foreach ($node as $key => $value) {
      $array[$key] = $value;
    }
  }
  else {
    $array = $node;
  }

  return $array;
}

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
181
    // Set some required fields:
Dries's avatar
 
Dries committed
182
    $node->created = time();
Dries's avatar
 
Dries committed
183
    $node->changed = time();
Dries's avatar
 
Dries committed
184 185
    $node->nid = db_result(db_query("SELECT MAX(nid) + 1 FROM node"));

Dries's avatar
 
Dries committed
186
    // Prepare the query:
Dries's avatar
 
Dries committed
187 188 189 190 191 192 193
    foreach ($node as $key => $value) {
      if (in_array($key, $fields)) {
        $k[] = check_query($key);
        $v[] = "'". check_query($value) ."'";
      }
    }

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

Dries's avatar
 
Dries committed
197
    // Call the node specific callback (if any):
Dries's avatar
 
Dries committed
198 199 200 201 202 203 204 205
    module_invoke($node->type, "insert", $node);
  }
  else {

    /*
    ** Update an existing node:
    */

Dries's avatar
 
Dries committed
206
    // Set some required fields:
Dries's avatar
 
Dries committed
207 208
    $node->changed = time();

Dries's avatar
 
Dries committed
209
    // Prepare the query:
Dries's avatar
 
Dries committed
210 211 212 213 214 215
    foreach ($node as $key => $value) {
      if (in_array($key, $fields)) {
        $q[] = check_query($key) ." = '". check_query($value) ."'";
      }
    }

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

Dries's avatar
 
Dries committed
219
    // Call the node specific callback (if any):
Dries's avatar
 
Dries committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    module_invoke($node->type, "update", $node);

  }

  /*
  ** Return the node ID:
  */

  return $node->nid;

}

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

  if (is_array($node)) {
    $node = node_object($node);
  }

  /*
  ** 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
257 258
function node_access($op, $node = 0) {

Dries's avatar
 
Dries committed
259 260
  if (user_access("administer nodes")) {
    return 1;
Dries's avatar
 
Dries committed
261
  }
Dries's avatar
 
Dries committed
262
  else {
Dries's avatar
 
Dries committed
263

Dries's avatar
 
Dries committed
264 265 266
    /*
    ** Convert the node to an object if necessary:
    */
Dries's avatar
 
Dries committed
267

Dries's avatar
 
Dries committed
268 269 270
    if (is_array($node)) {
      $node = node_object($node);
    }
Dries's avatar
 
Dries committed
271

Dries's avatar
 
Dries committed
272 273 274 275
    /*
    ** Construct a function:
    */

Dries's avatar
 
Dries committed
276 277 278 279 280 281 282 283
    if ($node->type) {
      $type = $node->type;
    }
    else {
      $type = $node;
    }

    $function = $type ."_access";
Dries's avatar
 
Dries committed
284 285 286 287 288 289 290

    if (function_exists($function)) {
      return $function($op, $node);
    }
    else {
      return 0;
    }
Dries's avatar
 
Dries committed
291 292 293
  }
}

Dries's avatar
 
Dries committed
294
function node_perm() {
Dries's avatar
 
Dries committed
295
  return array("administer nodes", "access content", "post content");
Dries's avatar
 
Dries committed
296 297
}

Dries's avatar
 
Dries committed
298
function node_search($keys) {
Dries's avatar
 
Dries committed
299
  global $PHP_SELF;
Dries's avatar
 
Dries committed
300 301 302

  $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
303
    $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
304 305 306 307 308
  }

  return $find;
}

Dries's avatar
 
Dries committed
309
function node_conf_options() {
Dries's avatar
 
Dries committed
310
  $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
311 312 313
  return $output;
}

Dries's avatar
CHANGES  
Dries committed
314
function node_conf_filters() {
Dries's avatar
 
Dries committed
315
  $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."));
Dries's avatar
 
Dries committed
316
  $output .= form_textfield(t("Allowed HTML tags"), "allowed_html", variable_get("allowed_html", "<a> <b> <dd> <dl> <dt> <i> <li> <ol> <u> <ul>"), 64, 128, 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
317
  $output .= "<hr />";
Dries's avatar
 
Dries committed
318
  $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
319
  $output .= "<hr />";
Dries's avatar
CHANGES  
Dries committed
320 321 322 323 324 325 326 327 328 329 330
  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
331 332 333 334 335
  $src = array("/\[\[(([^\|]*?)(\|([^\|]*?))?)\]\]/e");  // [link|description]
  $dst = array(format_tag('\\2', '\\4'));                // [link|description]
  return preg_replace($src, $dst, $text);
}

Dries's avatar
 
Dries committed
336
function node_filter_line($text) {
Dries's avatar
 
Dries committed
337

Dries's avatar
 
Dries committed
338
  /*
Dries's avatar
 
Dries committed
339 340 341 342 343 344 345
  ** 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
346 347 348
  */

  if (strstr($text, "<br />") || strstr($text, "<p>")) {
Dries's avatar
 
Dries committed
349
    $text = ereg_replace("[\r\n]", "", $text);
Dries's avatar
 
Dries committed
350 351 352 353 354 355 356 357 358
  }

  /*
  ** 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
359
  $text = eregi_replace("<p />", "\n", $text);
Dries's avatar
 
Dries committed
360 361

  /*
Dries's avatar
 
Dries committed
362
  ** Replace '\r\n' by '\n':
Dries's avatar
 
Dries committed
363 364 365 366 367 368 369 370 371 372 373
  */

  $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
374

Dries's avatar
 
Dries committed
375 376 377 378 379 380 381
  /*
  ** 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
382 383 384
  return trim($text);
}

Dries's avatar
CHANGES  
Dries committed
385 386 387
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
388
  return node_filter_line($text);
Dries's avatar
CHANGES  
Dries committed
389 390
}

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

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

Dries's avatar
 
Dries committed
397
  if ($type == "page" && user_access("post content")) {
Dries's avatar
 
Dries committed
398
    $links[] = "<a href=\"module.php?mod=node&op=add\">submit</a>";
Dries's avatar
 
Dries committed
399 400
  }

Dries's avatar
 
Dries committed
401
  if ($type == "node") {
Kjartan's avatar
Kjartan committed
402 403 404
    if ($node->links) {
      $links = $node->links;
    }
Dries's avatar
 
Dries committed
405

Dries's avatar
 
Dries committed
406
    if ($main == 1 && $node->teaser != $node->body) {
Dries's avatar
 
Dries committed
407
      $links[] = "<a href=\"node.php?id=$node->nid\">". t("read more") ."</a>";
Dries's avatar
 
Dries committed
408
    }
Dries's avatar
 
Dries committed
409 410

    if (user_access("administer nodes")) {
Dries's avatar
 
Dries committed
411
       $links[] = "<a href=\"admin.php?mod=node&op=edit&id=$node->nid\">". t("administer") ."</a>";
Dries's avatar
 
Dries committed
412
    }
Dries's avatar
 
Dries committed
413 414 415 416 417
  }

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

Dries's avatar
 
Dries committed
418
function node_admin_settings($edit = array()) {
Dries's avatar
 
Dries committed
419 420
  global $op;

Dries's avatar
 
Dries committed
421 422 423 424
  if ($op == t("Save configuration")) {
    /*
    ** Save the configuration options:
    */
Dries's avatar
Dries committed
425

Dries's avatar
 
Dries committed
426 427 428
    foreach ($edit as $name => $value) {
      variable_set($name, $value);
    }
Dries's avatar
 
Dries committed
429 430
  }

Dries's avatar
 
Dries committed
431 432 433 434
  if ($op == t("Reset to defaults")) {
    /*
    ** Reset the configuration options to their default value:
    */
Dries's avatar
 
Dries committed
435

Dries's avatar
 
Dries committed
436 437 438
    foreach ($edit as $name=>$value) {
      variable_del($name);
    }
Dries's avatar
 
Dries committed
439
  }
Dries's avatar
Dries committed
440

Dries's avatar
 
Dries committed
441
  $output .= "<h3>". t("Global node settings") ."</h3>";
Dries's avatar
 
Dries committed
442
  $output .= node_conf_options();
Dries's avatar
 
Dries committed
443 444 445

  foreach (module_list() as $name) {
    if (module_hook($name, "conf_options") && module_hook($name, "node")) {
Dries's avatar
 
Dries committed
446
      $output .= "<h3>". ucfirst(module_invoke($name, "node", "name") ." settings") ."</h3>";
Dries's avatar
 
Dries committed
447 448 449 450
      $output .= module_invoke($name, "conf_options");
    }
  }

Dries's avatar
 
Dries committed
451 452
  $output .= form_submit(t("Save configuration"));
  $output .= form_submit(t("Reset to defaults"));
Dries's avatar
Dries committed
453

Dries's avatar
 
Dries committed
454
  return form($output);
Dries's avatar
 
Dries committed
455 456
}

Dries's avatar
 
Dries committed
457
function node_admin_edit($node) {
Dries's avatar
 
Dries committed
458

Dries's avatar
 
Dries committed
459
  if (is_numeric($node)) {
Dries's avatar
 
Dries committed
460
    $node = node_load(array("nid" => $node));
Dries's avatar
 
Dries committed
461
  }
Dries's avatar
 
Dries committed
462

Dries's avatar
 
Dries committed
463 464 465
  /*
  ** Edit node:
  */
Dries's avatar
 
Dries committed
466

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

Dries's avatar
 
Dries committed
469
  $output .= node_form($node);
Dries's avatar
 
Dries committed
470

Dries's avatar
 
Dries committed
471 472 473 474 475 476 477 478 479
  /*
  ** 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
480
      $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
481 482 483 484
    }
    $output .= "</table>";
  }

Dries's avatar
 
Dries committed
485
  /*
Dries's avatar
 
Dries committed
486
  ** Display the node form extensions:
Dries's avatar
 
Dries committed
487
  */
Dries's avatar
 
Dries committed
488

Dries's avatar
 
Dries committed
489 490
  foreach (module_list() as $name) {
    $output .= module_invoke($name, "node_link", $node);
Dries's avatar
Dries committed
491 492
  }

Dries's avatar
 
Dries committed
493
  return $output;
Dries's avatar
 
Dries committed
494 495 496

}

Dries's avatar
 
Dries committed
497 498
function node_admin_nodes() {
  global $query;
Dries's avatar
 
Dries committed
499

Dries's avatar
 
Dries committed
500
  $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
501

Dries's avatar
 
Dries committed
502
  $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
503

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

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

Dries's avatar
 
Dries committed
510 511 512
  $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
513
    $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
514
  }
Dries's avatar
 
Dries committed
515
  $output .= "</table>";
Dries's avatar
 
Dries committed
516

Dries's avatar
 
Dries committed
517
  return $output;
Dries's avatar
Dries committed
518 519
}

Dries's avatar
 
Dries committed
520 521 522 523 524 525 526 527 528 529 530 531
/*
** 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
532 533 534
function node_revision_create($node) {
  global $user;

Dries's avatar
 
Dries committed
535 536 537 538 539
  /*
  ** '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
540
  if ($node->nid && $node->revision) {
Dries's avatar
 
Dries committed
541 542 543 544
    $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
545 546 547 548 549
  }

  return $node;
}

Dries's avatar
 
Dries committed
550 551 552
/*
** Roll-back to the revision with the specified revision number.
*/
Dries's avatar
 
Dries committed
553

Dries's avatar
 
Dries committed
554 555
function node_revision_rollback($node, $revision) {
  global $user;
Dries's avatar
 
Dries committed
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590

  /*
  ** 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
591
  watchdog("special", "$node->type: rollbacked to revision #$revision of '$node->title'");
Dries's avatar
 
Dries committed
592 593
}

Dries's avatar
 
Dries committed
594 595 596 597 598
/*
** Delete the revision with specified revision number.
*/

function node_revision_delete($node, $revision) {
Dries's avatar
 
Dries committed
599 600

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

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

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

Dries's avatar
 
Dries committed
607 608 609 610 611 612 613 614 615 616 617
/*
** 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
618 619
}

Dries's avatar
 
Dries committed
620
function node_admin() {
Dries's avatar
 
Dries committed
621
  global $op, $id, $revision, $edit;
Dries's avatar
 
Dries committed
622

Dries's avatar
 
Dries committed
623
  if (user_access("administer nodes")) {
Dries's avatar
 
Dries committed
624

Dries's avatar
 
Dries committed
625 626 627
    /*
    ** Compile a list of the administrative links:
    */
Dries's avatar
Dries committed
628

Dries's avatar
 
Dries committed
629 630 631 632
    $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
633

Dries's avatar
 
Dries committed
634
    print "<small>". implode(" &middot; ", $links) ."</small><hr />";
Dries's avatar
 
Dries committed
635 636 637 638 639 640

    switch ($op) {
      case "help":
        print node_help();
        break;
      case "search":
Dries's avatar
 
Dries committed
641
        print search_type("node", "admin.php?mod=node&op=search");
Dries's avatar
 
Dries committed
642
        break;
Dries's avatar
 
Dries committed
643 644 645 646
      case t("Save configuration"):
      case t("Reset to defaults"):
      case "settings":
        print node_admin_settings($edit);
Dries's avatar
 
Dries committed
647 648
        break;
      case "edit":
Dries's avatar
 
Dries committed
649
        print node_admin_edit($id);
Dries's avatar
 
Dries committed
650
        break;
Dries's avatar
 
Dries committed
651 652 653
      case "delete":
        print node_delete(array("nid" => $id));
        break;
Dries's avatar
 
Dries committed
654
      case "rollback revision":
Dries's avatar
 
Dries committed
655 656
        print node_revision_rollback(node_load(array("nid" => $id)), $revision);
        print node_admin_edit($id);
Dries's avatar
 
Dries committed
657 658
        break;
      case "delete revision":
Dries's avatar
 
Dries committed
659 660
        print node_revision_delete(node_load(array("nid" => $id)), $revision);
        print node_admin_edit($id);
Dries's avatar
 
Dries committed
661
        break;
Dries's avatar
 
Dries committed
662
      case t("Preview"):
Dries's avatar
 
Dries committed
663
        print node_preview($edit);
Dries's avatar
 
Dries committed
664
        break;
Dries's avatar
 
Dries committed
665
      case t("Submit"):
Dries's avatar
 
Dries committed
666 667 668
        print node_submit($edit);
        break;
      case t("Delete"):
Dries's avatar
 
Dries committed
669
        print node_delete($edit);
Dries's avatar
 
Dries committed
670
        break;
Dries's avatar
 
Dries committed
671
      default:
Dries's avatar
 
Dries committed
672
        print node_admin_nodes();
Dries's avatar
 
Dries committed
673 674 675 676
    }
  }
  else {
    print message_access();
Dries's avatar
 
Dries committed
677 678 679
  }
}

Dries's avatar
 
Dries committed
680 681 682 683
function node_block() {
  global $theme;

  $block[0][subject] = t("Syndicate");
Dries's avatar
 
Dries committed
684
  $block[0][content] = "<div align=\"center\"><a href=\"module.php?mod=node&op=feed\"><img src=\"". $theme->image("xml.gif") ."\" width=\"36\" height=\"14\" border=\"0\" alt=\"XML\" /></a></div>\n";
Dries's avatar
 
Dries committed
685 686 687 688 689 690
  $block[0][info] = "Syndicate";

  return $block;
}

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

Dries's avatar
 
Dries committed
692
  $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
693 694

  while ($node = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
695
    $item = node_load(array("nid" => $node->nid, "type" => $node->type));
Dries's avatar
 
Dries committed
696 697 698

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

Dries's avatar
 
Dries committed
699
    $items .= format_rss_item($item->title, $link, $item->teaser);
Dries's avatar
 
Dries committed
700 701 702
  }

  $output .= "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
Dries's avatar
 
Dries committed
703
  // $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
704
  $output .= "<rss version=\"0.91\">\n";
Dries's avatar
 
Dries committed
705
  $output .= format_rss_channel(variable_get("site_name", "drupal"), path_uri(), variable_get("site_slogan", ""), $items);
Dries's avatar
 
Dries committed
706 707
  $output .= "</rss>\n";

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

Dries's avatar
 
Dries committed
710 711 712 713
  print $output;

}

Dries's avatar
 
Dries committed
714

715
function node_validate($node, &$error) {
Dries's avatar
 
Dries committed
716 717 718 719 720 721 722

  global $user;

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

Dries's avatar
 
Dries committed
723
  $node = node_object($node);
Dries's avatar
 
Dries committed
724 725 726 727 728

  /*
  ** Validate the title field:
  */

Dries's avatar
 
Dries committed
729
  if (isset($node->title) && !$node->title) {
Dries's avatar
 
Dries committed
730 731 732 733 734 735 736 737 738
    $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
739 740
    if (!$node->created) {
      $node->created = time();
Dries's avatar
 
Dries committed
741 742
    }

Dries's avatar
 
Dries committed
743 744
    if (!$node->date) {
      $node->date = date("M j, Y g:i a", $node->created);
Dries's avatar
 
Dries committed
745 746 747 748 749 750
    }

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

Dries's avatar
 
Dries committed
751 752 753 754 755 756 757 758 759
    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
760
      $node->uid = $account->uid;
Dries's avatar
 
Dries committed
761 762
    }
    else {
Dries's avatar
 
Dries committed
763
      $error["name"] = "<div style=\"color: red;\">". sprintf(t("The name '%s' does not exist."), $node->name) ."</div>";
Dries's avatar
 
Dries committed
764 765 766 767 768 769
    }

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

Dries's avatar
 
Dries committed
770 771
    if (strtotime($node->date) > 1000) {
      $node->created = strtotime($node->date);
Dries's avatar
 
Dries committed
772 773 774 775
    }
    else {
      $error["date"] = "<div style=\"color: red;\">". t("You have to specifiy a valid date.") ."</div>";
    }
Dries's avatar
 
Dries committed
776

Dries's avatar
 
Dries committed
777 778
  }

Dries's avatar
 
Dries committed
779
  return $node;
Dries's avatar
 
Dries committed
780 781
}

Dries's avatar
 
Dries committed
782

Dries's avatar
 
Dries committed
783 784
function node_form($edit) {

Dries's avatar
 
Dries committed
785 786 787 788 789 790 791
  /*
  ** 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
792 793 794 795
  /*
  ** Validate the node:
  */

796
  $edit = node_validate($edit, $error);
Dries's avatar
 
Dries committed
797

Dries's avatar
 
Dries committed
798 799 800 801 802 803 804 805
  /*
  ** Generate a teaser when necessary:
  */

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

Dries's avatar
 
Dries committed
806 807 808 809 810 811
  /*
  ** Get the node specific bits:
  */

  $function = $edit->type ."_form";
  if (function_exists($function)) {
812
    $form .= $function($edit, $help, $error);
Dries's avatar
 
Dries committed
813 814 815 816 817 818 819 820 821 822
  }

  /*
  ** Add the help text:
  */

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

Dries's avatar
 
Dries committed
823 824 825 826
  $output .= "<table border=\"0\" cellpadding=\"2\" cellspacing=\"2\">";
  $output .= " <tr>";
  $output .= "  <td valign=\"top\">";

Dries's avatar
 
Dries committed
827 828 829 830 831 832 833
  /*
  ** Add the default fields:
  */

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

  /*
Dries's avatar
 
Dries committed
834
  ** Add the node specific fields:
Dries's avatar
 
Dries committed
835 836
  */

Dries's avatar
 
Dries committed
837
  $output .= $form;
Dries's avatar
 
Dries committed
838 839 840 841 842 843 844 845 846

  /*
  ** Add the hidden fields:
  */

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

Dries's avatar
 
Dries committed
847 848 849 850 851
  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
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
    $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
871
  if ($edit->nid && node_access("delete", $edit)) {
Dries's avatar
 
Dries committed
872 873 874 875 876 877 878 879
    $output .= form_submit(t("Delete"));
  }

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

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

Dries's avatar
 
Dries committed
882 883 884
    $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
885
    $output .= form_select(t("Set public/published"), "status", $edit->status, array("Disabled", "Enabled"));
Dries's avatar
 
Dries committed
886
    $output .= form_select(t("Queue for moderation"), "moderate", $edit->moderate, array("Disabled", "Enabled"));
Dries's avatar
 
Dries committed
887
    $output .= form_select(t("Promote to front page"), "promote", $edit->promote, array("Disabled", "Enabled"));
Dries's avatar
 
Dries committed
888
    $output .= form_select(t("Allow users comments"), "comment", $edit->comment, array("Disabled", "Enabled"));
Dries's avatar
 
Dries committed
889
    $output .= form_select(t("Create new revision"), "revision", $edit->revision, array("Disabled", "Enabled"));
Dries's avatar
 
Dries committed
890 891
  }

Dries's avatar
 
Dries committed
892 893 894 895
  $output .= "  </td>";
  $output .= " </tr>";
  $output .= "</table>";

Dries's avatar
 
Dries committed
896 897 898 899 900 901
  return form($output);
}

function node_add($type) {
  global $user;

Dries's avatar
 
Dries committed
902
  /*
Dries's avatar
 
Dries committed
903
  ** If a node type has been specified, validate it existence.  If no
Dries's avatar
 
Dries committed
904 905 906
  ** (valid) node type has been provied, display a node type overview.
  */

Dries's avatar
 
Dries committed
907
  if ($type && node_access("create", $type)) {
Dries's avatar
 
Dries committed
908
    $output = node_form(array("uid" => $user->uid, "name" => $user->name, "type" => $type));
Dries's avatar
 
Dries committed
909 910
  }
  else {
Dries's avatar
 
Dries committed
911

Dries's avatar
 
Dries committed
912 913 914
    /*
    ** Compile a list with the different node types and their explanation:
    */
Dries's avatar
 
Dries committed
915

Dries's avatar
 
Dries committed
916
    foreach (module_list() as $name) {
Dries's avatar
 
Dries committed
917 918 919 920 921
      if (module_hook($name, "node") && node_access("create", array("type" => $name))) {
        $output .= "<li>";
        $output .= " <a href=\"module.php?mod=node&op=add&type=$name\">". module_invoke($name, "node", "name") ."</a>";
        $output .= " <div style=\"margin-left: 20px;\">". module_invoke($name, "node", "description") ."</div>";
        $output .= "</li>";
Dries's avatar
 
Dries committed
922
      }
Dries's avatar
 
Dries committed
923 924
    }

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

Dries's avatar
 
Dries committed
927 928 929 930 931 932 933 934 935 936
  }

  return $output;
}

function node_edit($id) {
  global $user;

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

Dries's avatar
 
Dries committed
937 938 939 940 941 942 943 944
  if (node_access("update", $node)) {
    $output = node_form($node);
  }
  else {
    $output = message_access();
  }

  return $output;
Dries's avatar
 
Dries committed
945 946
}

Dries's avatar
 
Dries committed
947 948 949 950 951 952 953
function node_preview($node) {

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

  $node = node_object($node);
Dries's avatar
 
Dries committed
954 955 956 957 958

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

Dries's avatar
 
Dries committed
959 960 961 962 963 964 965 966
  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
967 968
    }
    else {
Dries's avatar
 
Dries committed
969
      $node->uid = 0; // anonymous user
Dries's avatar
 
Dries committed
970
    }
Dries's avatar
 
Dries committed
971
  }
Dries's avatar
 
Dries committed
972
  else if ($node->uid) {
Dries's avatar
 
Dries committed
973 974
    $user = user_load(array("uid" => $node->uid));
    $node->name = $user->name;
Dries's avatar
 
Dries committed
975 976 977 978 979 980
  }

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

Dries's avatar
 
Dries committed
981 982
  if (empty($node->nid)) {
    $node->created = time();
Dries's avatar
 
Dries committed
983 984
  }

Dries's avatar
 
Dries committed
985 986 987 988
  /*
  ** Apply the required filters:
  */

Dries's avatar
 
Dries committed
989
  if ($node->nid) {
Dries's avatar
 
Dries committed
990
    $view = array_merge($node, module_invoke($node->type, "save", "update", $node));
Dries's avatar
 
Dries committed
991 992
  }
  else {
Dries's avatar
 
Dries committed
993
    $view = array_merge($node, module_invoke($node->type, "save", "create", $node));
Dries's avatar
 
Dries committed
994 995
  }

Dries's avatar
 
Dries committed
996 997 998 999
  /*
  ** Display a preview of the node:
  */

Dries's avatar
 
Dries committed
1000
  node_view($view);
Dries's avatar
 
Dries committed
1001

Dries's avatar
 
Dries committed
1002
  return node_form($node);
Dries's avatar
 
Dries committed
1003 1004
}

Dries's avatar
 
Dries committed
1005
function node_submit($node) {
Dries's avatar
 
Dries committed
1006
  global $theme, $user;
Dries's avatar
 
Dries committed
1007

Dries's avatar
 
Dries committed
1008
  if (user_access("post content")) {
Dries's avatar
 
Dries committed
1009

Dries's avatar
 
Dries committed
1010 1011 1012 1013
    /*
    ** Verify a user's submission rate and avoid duplicate nodes being
    ** inserted:
    */
Dries's avatar
 
Dries committed
1014

Dries's avatar
 
Dries committed
1015
    throttle("node", variable_get("max_node_rate", 900));
Dries's avatar
 
Dries committed
1016

Dries's avatar
 
Dries committed
1017 1018 1019
    /*
    ** Fixup the node when required:
    */
Dries's avatar
 
Dries committed
1020

1021
    $node = node_validate($node, $error);
Dries's avatar
 
Dries committed
1022

Dries's avatar
 
Dries committed
1023
    /*
Dries's avatar
 
Dries committed
1024
    ** Create a new revision when required:
Dries's avatar
 
Dries committed
1025 1026
    */

Dries's avatar
 
Dries committed
1027 1028 1029
    $node = node_revision_create($node);

    if ($node->nid) {
Dries's avatar
 
Dries committed
1030 1031

      /*
Dries's avatar
 
Dries committed
1032 1033
      ** Check whether the current user has the proper access rights to
      ** perform this operation:
Dries's avatar
 
Dries committed
1034 1035
      */

Dries's avatar
 
Dries committed
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
      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
1047
          $fields = array("nid", "uid" => ($user->uid ? $user->uid : 0), "body", "teaser", "title", "type" => $node->type);
Dries's avatar
 
Dries committed
1048 1049
        }

Dries's avatar
 
Dries committed
1050
        $nid = node_save($node, array_merge($fields, module_invoke($node->type, "save", "update", $node)));
Dries's avatar
 
Dries committed
1051 1052 1053

        watchdog("special", "$node->type: updated '$node->title'");
        $output = t("The node has been updated.");
Dries's avatar
 
Dries committed
1054 1055
      }
      else {
Dries's avatar
 
Dries committed
1056 1057
        watchdog("warning", "$node->type: not authorized to update node");
        $output = t("You are not authorized to update this node.");
Dries's avatar
 
Dries committed
1058 1059
      }

Dries's avatar
 
Dries committed
1060 1061 1062
    }
    else {

Dries's avatar
 
Dries committed
1063 1064 1065 1066
      /*
      ** Check whether the current user has the proper access rights to
      ** perform this operation:
      */
Dries's avatar
 
Dries committed
1067

Dries's avatar
 
Dries committed
1068
      if (node_access("create", $node)) {
Dries's avatar
 
Dries committed
1069

Dries's avatar
 
Dries committed
1070 1071 1072 1073
        /*
        ** 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
1074

Dries's avatar
 
Dries committed
1075 1076 1077 1078
        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
1079
          $fields = array("uid" => ($user->uid ? $user->uid : 0), "body", "comment" => 1, "teaser", "title", "type" => $node->type);
Dries's avatar
 
Dries committed
1080 1081
        }

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

Dries's avatar
 
Dries committed
1084 1085
        watchdog("special", "$node->type: added '$node->title'");
        $output = t("Thanks for your submission.");
Dries's avatar
 
Dries committed
1086 1087
      }
      else {
Dries's avatar
 
Dries committed
1088 1089