Commit a2e69109 authored by Dries's avatar Dries

- Made the node forms support "help texts": it is not possible to configure
  Drupal to display submission guidelines, or any other kind of explanation
  such as "NO TEST POSTS", for example.

- Added node versioning: it is possible to create revisions, to view old
  revisions and to roll-back to older revisions.  You'll need to apply a
  SQL update.

  I'm going to work on the book module now, so I might be changing a few
  things to enable collaborative, moderated revisions - but feel free to
  send some first feedback, if you like.

- Added some configuration options which can be used to set the minimum
  number of words a blog/story should consist of.  Hopefully this will
  be usefull to stop the (almost empty) test blogs.

- Various improvements:
   + Fine-tuned new node permission system.
   + Fine-tuned the functions in node.inc.
   + Fine-tuned some forms.
   + XHTML-ified some code.
parent 4d8b485f
<?php
// $Id$
// Security check:
if (strstr($id, " ") || strstr($pid, " ") || strstr($lid, " ") || strstr($mode, " ") || strstr($order, " ") || strstr($threshold, " ")) {
watchdog("error", "comment: attempt to provide malicious input through URI");
exit();
}
$cmodes = array(1 => "List - min", 2 => "List - max", 3 => "Threaded - min", 4 => "Threaded - max");
$corder = array(1 => "Date - new", 2 => "Date - old", 3 => "Rate - high", 4 => "Rate - low");
......
......@@ -279,7 +279,11 @@ function form($form, $method = "post", $action = 0, $options = 0) {
}
function form_item($title, $value, $description = 0) {
return ($description) ? "<b>$title:</b><br />$value<br /><small><i>$description</i></small><p />\n" : "<b>$title:</b><br />$value<p />\n";
return ($title ? "<b>$title:</b><br />" : "") . $value . ($description ? "<br /><small><i>$description</i></small>" : "") ."<p />\n";
}
function form_checkbox($title, $name, $value, $description = 0) {
return form_item(0, "<input type=\"checkbox\" name=\"edit[$name]\" ". ($value ? " checked=\"checked\"" : "") ." /> $title", $description);
}
function form_textfield($title, $name, $value, $size, $maxlength, $description = 0) {
......
......@@ -84,15 +84,33 @@ function node_array($node) {
function node_load($conditions) {
// prepare query:
/*
** Turn the conditions into a query:
*/
foreach ($conditions as $key => $value) {
$cond[] = "n.". check_query($key) ." = '". check_query($value) ."'";
}
// retrieve the node:
/*
** 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 LEFT JOIN comments c ON c.lid = n.nid WHERE ". implode(" AND ", $cond)));
// call the node specific callback (if any):
/*
** Unserialize the revisions field:
*/
if ($node->revisions) {
$node->revisions = unserialize($node->revisions);
}
/*
** Call the node specific callback (if any) and piggy-back to
** results to the node:
*/
if ($extra = module_invoke($node->type, "load", $node)) {
foreach ($extra as $key => $value) {
$node->$key = $value;
......@@ -105,7 +123,7 @@ function node_load($conditions) {
function node_save($node, $filter) {
$fields = array("nid", "uid", "type", "title", "teaser", "body", "status", "comment", "promote", "moderate", "created", "changed");
$fields = array("nid", "uid", "type", "title", "teaser", "body", "revisions", "status", "comment", "promote", "moderate", "created", "changed");
foreach ($filter as $key => $value) {
/*
......@@ -115,16 +133,31 @@ function node_save($node, $filter) {
*/
if (is_numeric($key)) {
$edit->$value = $node->$value;
if (isset($node->$value)) {
// The above check is mandatory.
$edit->$value = check_query($node->$value);
}
}
else {
$edit->$key = $value;
if (isset($value)) {
// The above check is mandatory.
$edit->$key = check_query($value);
}
}
}
$node = $edit;
/*
** Serialize the revisions field:
*/
if ($node->revisions) {
$node->revisions = serialize($node->revisions);
}
if (empty($node->nid)) {
/*
** Verify a user's submission rate and avoid duplicate nodes being
** inserted:
......@@ -143,8 +176,8 @@ function node_save($node, $filter) {
// prepare the query:
foreach ($node as $key => $value) {
if (in_array($key, $fields)) {
$k[] = check_query($key);
$v[] = "'". check_query($value) ."'";
$k[] = $key;
$v[] = "'$value'";
}
}
......@@ -168,12 +201,12 @@ function node_save($node, $filter) {
// prepare the query:
foreach ($node as $key => $value) {
if (in_array($key, $fields)) {
$q[] = check_query($key) ." = '". check_query($value) ."'";
$q[] = "$key = '$value'";
}
}
// update the node in the database:
db_query("UPDATE node SET ". implode(", ", $q) ." WHERE nid = '". check_query($node->nid) ."'");
db_query("UPDATE node SET ". implode(", ", $q) ." WHERE nid = '$node->nid'");
// call the node specific callback (if any):
module_invoke($node->type, "update", $node);
......@@ -189,23 +222,6 @@ function node_save($node, $filter) {
}
function node_delete($node) {
if (is_array($node)) {
$node = node_object($node);
}
// delete the node and its comments:
db_query("DELETE FROM node WHERE nid = '$node->nid'");
db_query("DELETE FROM comments WHERE lid = '$node->nid'");
db_query("DELETE FROM moderate WHERE nid = '$node->nid'");
// call the node specific callback (if any):
module_invoke($node->type, "delete", &$node);
watchdog("special", "node: deleted '$node->title'");
}
function node_view($node, $main = 0) {
global $theme;
......
<?php
// $Id$
function blog_conf_options() {
$output .= form_textarea("Explanation or submission guidelines", "blog_help", variable_get("blog_help", ""), 55, 4, "This text will be displayed at the top of the blog submission form. Useful for helping or instructing your users.");
$output .= form_select(t("Minimum number of words in a node"), "minimum_blog_size", variable_get("minimum_node_size", 0), array(0 => "0 words", 10 => "10 words", 25 => "25 words", 50 => "50 words", 75 => "75 words", 100 => "100 words", 125 => "125 words", 150 => "150 words", 175 => "175 words", 200 => "200 words"), t("The minimum number of words a personal blog entry should consist of. This can be useful to rule out submissions that do not meet the site's standards, such as short test post."));
return $output;
}
function blog_node($field) {
global $user;
......@@ -13,7 +21,7 @@ function blog_access($op, $node) {
global $user;
if ($op == "view") {
return $node->nid && $node->status && !$node->moderate;
return ($node->nid && $node->status && !$node->moderate);
}
if ($op == "create") {
......@@ -21,11 +29,11 @@ function blog_access($op, $node) {
}
if ($op == "update") {
return user_access("administer nodes") || ($user->uid == $node->uid);
return ($user->uid == $node->uid);
}
if ($op == "delete") {
return user_access("administer nodes") || ($user->uid == $node->uid);
return ($user->uid == $node->uid);
}
}
......@@ -36,10 +44,6 @@ function blog_help() {
<?php
}
function blog_perm() {
return array("administer blogs", "access blogs", "post blogs");
}
function blog_feed_user($uid = 0, $date = 0) {
global $user;
......@@ -122,7 +126,7 @@ function blog_page_user($uid = 0, $date = 0) {
$links[] = "<a href=\"module.php?mod=node&op=edit&id=$blog->nid\">". t("edit") ."</a>";
}
if ($user->uid && user_access("post blogs")) {
if ($user->uid) {
$links[] = "<a href=\"module.php?mod=node&op=add&type=blog&nid=$blog->nid\">". t("blog it") ."</a>";
}
......@@ -159,7 +163,7 @@ function blog_page_last() {
$links[] = "<a href=\"module.php?mod=node&op=edit&id=$blog->nid\">". t("edit") ."</a>";
}
if ($user->uid && user_access("post blogs")) {
if ($user->uid) {
$links[] = "<a href=\"module.php?mod=node&op=add&type=blog&nid=$blog->nid\">". t("blog it") ."</a>";
}
......@@ -178,15 +182,33 @@ function blog_page_last() {
$theme->box(t("User blogs"), $output, "main");
}
function blog_form($node, $error) {
function blog_form($node, $help, $error) {
global $nid, $iid;
if ($node->body) {
if (count(explode(" ", $node->body)) < variable_get("minimum_node_size", 0)) {
if (isset($node->body)) {
/*
** Validate the size of the blog:
*/
if (count(explode(" ", $node->body)) < variable_get("minimum_blog_size", 0)) {
$error["body"] = "<div style=\"color: red;\">". t("The body of your blog is too short.") ."</div>";
}
}
else {
/*
** Carry out some explanation or submission guidelines:
*/
$help = variable_get("blog_help", "");
/*
** If the user clicked a "blog it" link, we load the data from the
** database and quote it in the blog:
*/
if ($nid && $blog = node_load(array("nid" => $nid))) {
$node->body = "<i>". $blog->body ."</i> [<a href=\"module.php?mod=blog&id=$blog->uid&date=$blog->created\">$blog->name</a>]";
}
......@@ -215,7 +237,7 @@ function blog_save($node) {
function blog_page() {
global $theme, $id, $op, $date;
if (user_access("access blogs")) {
if (user_access("access content")) {
switch ($op) {
case "feed":
if ($id) {
......@@ -247,11 +269,11 @@ function blog_page() {
function blog_link($type, $node = 0) {
global $user;
if ($type == "page" && user_access("access blogs")) {
if ($type == "page" && user_access("access content")) {
$links[] = "<a href=\"module.php?mod=blog\">". t("user blogs") ."</a>";
}
if ($type == "menu" && user_access("post blogs")) {
if ($type == "menu") {
$links[] = "<a href=\"module.php?mod=node&op=add&type=blog\">". t("add blog entry") ."</a>";
$links[] = "<a href=\"module.php?mod=blog&op=view&id=$user->uid\">". t("view your blog") ."</a>";
}
......
<?php
// $Id$
function blog_conf_options() {
$output .= form_textarea("Explanation or submission guidelines", "blog_help", variable_get("blog_help", ""), 55, 4, "This text will be displayed at the top of the blog submission form. Useful for helping or instructing your users.");
$output .= form_select(t("Minimum number of words in a node"), "minimum_blog_size", variable_get("minimum_node_size", 0), array(0 => "0 words", 10 => "10 words", 25 => "25 words", 50 => "50 words", 75 => "75 words", 100 => "100 words", 125 => "125 words", 150 => "150 words", 175 => "175 words", 200 => "200 words"), t("The minimum number of words a personal blog entry should consist of. This can be useful to rule out submissions that do not meet the site's standards, such as short test post."));
return $output;
}
function blog_node($field) {
global $user;
......@@ -13,7 +21,7 @@ function blog_access($op, $node) {
global $user;
if ($op == "view") {
return $node->nid && $node->status && !$node->moderate;
return ($node->nid && $node->status && !$node->moderate);
}
if ($op == "create") {
......@@ -21,11 +29,11 @@ function blog_access($op, $node) {
}
if ($op == "update") {
return user_access("administer nodes") || ($user->uid == $node->uid);
return ($user->uid == $node->uid);
}
if ($op == "delete") {
return user_access("administer nodes") || ($user->uid == $node->uid);
return ($user->uid == $node->uid);
}
}
......@@ -36,10 +44,6 @@ function blog_help() {
<?php
}
function blog_perm() {
return array("administer blogs", "access blogs", "post blogs");
}
function blog_feed_user($uid = 0, $date = 0) {
global $user;
......@@ -122,7 +126,7 @@ function blog_page_user($uid = 0, $date = 0) {
$links[] = "<a href=\"module.php?mod=node&op=edit&id=$blog->nid\">". t("edit") ."</a>";
}
if ($user->uid && user_access("post blogs")) {
if ($user->uid) {
$links[] = "<a href=\"module.php?mod=node&op=add&type=blog&nid=$blog->nid\">". t("blog it") ."</a>";
}
......@@ -159,7 +163,7 @@ function blog_page_last() {
$links[] = "<a href=\"module.php?mod=node&op=edit&id=$blog->nid\">". t("edit") ."</a>";
}
if ($user->uid && user_access("post blogs")) {
if ($user->uid) {
$links[] = "<a href=\"module.php?mod=node&op=add&type=blog&nid=$blog->nid\">". t("blog it") ."</a>";
}
......@@ -178,15 +182,33 @@ function blog_page_last() {
$theme->box(t("User blogs"), $output, "main");
}
function blog_form($node, $error) {
function blog_form($node, $help, $error) {
global $nid, $iid;
if ($node->body) {
if (count(explode(" ", $node->body)) < variable_get("minimum_node_size", 0)) {
if (isset($node->body)) {
/*
** Validate the size of the blog:
*/
if (count(explode(" ", $node->body)) < variable_get("minimum_blog_size", 0)) {
$error["body"] = "<div style=\"color: red;\">". t("The body of your blog is too short.") ."</div>";
}
}
else {
/*
** Carry out some explanation or submission guidelines:
*/
$help = variable_get("blog_help", "");
/*
** If the user clicked a "blog it" link, we load the data from the
** database and quote it in the blog:
*/
if ($nid && $blog = node_load(array("nid" => $nid))) {
$node->body = "<i>". $blog->body ."</i> [<a href=\"module.php?mod=blog&id=$blog->uid&date=$blog->created\">$blog->name</a>]";
}
......@@ -215,7 +237,7 @@ function blog_save($node) {
function blog_page() {
global $theme, $id, $op, $date;
if (user_access("access blogs")) {
if (user_access("access content")) {
switch ($op) {
case "feed":
if ($id) {
......@@ -247,11 +269,11 @@ function blog_page() {
function blog_link($type, $node = 0) {
global $user;
if ($type == "page" && user_access("access blogs")) {
if ($type == "page" && user_access("access content")) {
$links[] = "<a href=\"module.php?mod=blog\">". t("user blogs") ."</a>";
}
if ($type == "menu" && user_access("post blogs")) {
if ($type == "menu") {
$links[] = "<a href=\"module.php?mod=node&op=add&type=blog\">". t("add blog entry") ."</a>";
$links[] = "<a href=\"module.php?mod=blog&op=view&id=$user->uid\">". t("view your blog") ."</a>";
}
......
......@@ -10,10 +10,9 @@ function book_node($field) {
}
function book_access($op, $node) {
global $user;
if ($op == "view") {
return $node->nid && $node->status && !$node->moderate;
return ($node->nid && $node->status && !$node->moderate);
}
if ($op == "create") {
......@@ -24,10 +23,6 @@ function book_access($op, $node) {
return 1;
}
if ($op == "delete") {
return user_access("adminster nodes");
}
}
function book_link($type) {
......@@ -155,7 +150,7 @@ function book_toc($parent = "", $indent = "", $toc = array()) {
return $toc;
}
function book_form($node, $error) {
function book_form($node, $help, $error) {
global $user;
$output .= form_select(t("Parent"), "parent", $node->parent, book_toc(), t("The parent subject or category the page belongs in."));
......
......@@ -10,10 +10,9 @@ function book_node($field) {
}
function book_access($op, $node) {
global $user;
if ($op == "view") {
return $node->nid && $node->status && !$node->moderate;
return ($node->nid && $node->status && !$node->moderate);
}
if ($op == "create") {
......@@ -24,10 +23,6 @@ function book_access($op, $node) {
return 1;
}
if ($op == "delete") {
return user_access("adminster nodes");
}
}
function book_link($type) {
......@@ -155,7 +150,7 @@ function book_toc($parent = "", $indent = "", $toc = array()) {
return $toc;
}
function book_form($node, $error) {
function book_form($node, $help, $error) {
global $user;
$output .= form_select(t("Parent"), "parent", $node->parent, book_toc(), t("The parent subject or category the page belongs in."));
......
......@@ -8,12 +8,9 @@ function forum_node($field) {
}
function forum_access($op, $node) {
if ($op == "view") {
return $node->nid && $node->status && !$node->moderate;
return ($node->nid && $node->status && !$node->moderate);
}
return user_access("adminster nodes");
}
function forum_link($type) {
......@@ -30,15 +27,13 @@ function forum_view($node) {
$theme->box(t("Discussion forum"), $output);
}
function forum_form($node, $error) {
function forum_form($node, $help, $error) {
$output .= form_textarea("Body", "body", $node->body, 60, 10);
return $output;
}
function forum_save() {
if ($node->nid) {
return array();
}
......@@ -63,13 +58,13 @@ function forum_page() {
if (user_access("access content")) {
$result = db_query("SELECT nid FROM node WHERE type = 'forum' ORDER BY title");
$output .= "<TABLE BORDER=\"0\" CELLSPACING=\"4\" CELLPADDING=\"4\">\n";
$output .= " <TR><TH>". t("Forum") ."</TH><TH>". t("Comments") ."</TH><TH>". t("Last comment") ."</TH></TR>";
$output .= "<table border=\"0\" cellspacing=\"4\" cellpadding=\"4\">";
$output .= " <tr><th>". t("Forum") ."</th><th>". t("Comments") ."</th><th>". t("Last comment") ."</th></tr>";
while ($node = db_fetch_object($result)) {
$node = node_load(array("nid" => $node->nid));
$output .= " <TR><TD><A HREF=\"node.php?id=$node->nid\">". check_output($node->title) ."</A><BR><SMALL>". check_output($node->body, 1) ."</SMALL></TD><TD ALIGN=\"center\">". forum_num_comments($node->nid) ."</TD><TD ALIGN=\"center\">". forum_last_comment($node->nid) ."</TD></TR>";
$output .= " <tr><td><a href=\"node.php?id=$node->nid\">". check_output($node->title) ."</a><br /><small>". check_output($node->body, 1) ."</small></td><td align=\"center\">". forum_num_comments($node->nid) ."</td><td align=\"center\">". forum_last_comment($node->nid) ."</td></tr>";
}
$output .= "</TABLE>\n";
$output .= "</table>";
$theme->header();
$theme->box(t("Discussion forum"), $output);
......
......@@ -8,12 +8,9 @@ function forum_node($field) {
}
function forum_access($op, $node) {
if ($op == "view") {
return $node->nid && $node->status && !$node->moderate;
return ($node->nid && $node->status && !$node->moderate);
}
return user_access("adminster nodes");
}
function forum_link($type) {
......@@ -30,15 +27,13 @@ function forum_view($node) {
$theme->box(t("Discussion forum"), $output);
}
function forum_form($node, $error) {
function forum_form($node, $help, $error) {
$output .= form_textarea("Body", "body", $node->body, 60, 10);
return $output;
}
function forum_save() {
if ($node->nid) {
return array();
}
......@@ -63,13 +58,13 @@ function forum_page() {
if (user_access("access content")) {
$result = db_query("SELECT nid FROM node WHERE type = 'forum' ORDER BY title");
$output .= "<TABLE BORDER=\"0\" CELLSPACING=\"4\" CELLPADDING=\"4\">\n";
$output .= " <TR><TH>". t("Forum") ."</TH><TH>". t("Comments") ."</TH><TH>". t("Last comment") ."</TH></TR>";
$output .= "<table border=\"0\" cellspacing=\"4\" cellpadding=\"4\">";
$output .= " <tr><th>". t("Forum") ."</th><th>". t("Comments") ."</th><th>". t("Last comment") ."</th></tr>";
while ($node = db_fetch_object($result)) {
$node = node_load(array("nid" => $node->nid));
$output .= " <TR><TD><A HREF=\"node.php?id=$node->nid\">". check_output($node->title) ."</A><BR><SMALL>". check_output($node->body, 1) ."</SMALL></TD><TD ALIGN=\"center\">". forum_num_comments($node->nid) ."</TD><TD ALIGN=\"center\">". forum_last_comment($node->nid) ."</TD></TR>";
$output .= " <tr><td><a href=\"node.php?id=$node->nid\">". check_output($node->title) ."</a><br /><small>". check_output($node->body, 1) ."</small></td><td align=\"center\">". forum_num_comments($node->nid) ."</td><td align=\"center\">". forum_last_comment($node->nid) ."</td></tr>";
}
$output .= "</TABLE>\n";
$output .= "</table>";
$theme->header();
$theme->box(t("Discussion forum"), $output);
......
......@@ -16,25 +16,31 @@ function node_help() {
function node_access($op, $node = 0) {
/*
** Convert the node to an object if necessary:
*/
if (is_array($node)) {
$node = node_object($node);
if (user_access("administer nodes")) {
return 1;
}
else {
/*
** Construct a function:
*/
/*
** Convert the node to an object if necessary:
*/
$function = $node->type ."_access";
if (is_array($node)) {
$node = node_object($node);
}
if (function_exists($function)) {
return $function($op, $node);
}
else {
return 0;
/*
** Construct a function:
*/
$function = $node->type ."_access";
if (function_exists($function)) {
return $function($op, $node);
}
else {
return 0;
}
}
}
......@@ -56,7 +62,6 @@ function node_search($keys) {
function node_conf_options() {
$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."));