diff --git a/CHANGELOG b/CHANGELOG index 62abda7f277..28072fdac15 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,23 +1,27 @@ drupal x.xx, xx/xx/xxxx ----------------------- - major overhaul of the entire underlying design: - * everything is based on nodes - * introduced links/drupal tags + * everything is based on nodes: nodes are a conceptual "black box" to couple and manage different types of content and that promotes reusing existing code, thus reducing the complexity and size of drupal as well as improving long-term stability. + * introduced links/drupal tags: [[link]] - rewrote submission/moderation queue: * renamed submission.module to moderation.module * updated submission forms -- added a "book module": - * merged documentation and FAQ module into a book module +- removed FAQ and documentation module and merged them into a "book module": + * allows collaborative book writing +- removed ban module and integrated it in account.module as "access control": + * access control is based on much more powerful regular expressions (regex) now rather than on MySQL pattern matching. - various updates: * added preview functionality when submitting new content (such as a story) from the administration pages. * made the administration section only show those links a user has access to. - * improved account module + * improved account module: + + added "acess control" to allow/deny certain usernames/e-mail addresses/hostnames * improved comment module * improved story module: - + stories can now be permanently deleted + + added preview functionality for administrators + + made it possible to permanently delete stories * improved themes: + W3C validation on a best effort basis - + added goofy theme + + added theme "goofy" - revised documentation drupal 2.00, 15/03/2001 @@ -56,10 +60,10 @@ drupal 2.00, 15/03/2001 * improved database abstraction layer * improved themes: + W3C validation on a best effort basis - + added example theme - * added CREDITS file - * added directory "misc" + + added theme "example" (alas "Stone Age") * added new scripts to directory "scripts" + * added directory "misc" + * added CREDITS file - revised documentation drupal 1.00, 15/01/2001 diff --git a/account.php b/account.php index bf598661044..3bd1e900094 100644 --- a/account.php +++ b/account.php @@ -24,7 +24,7 @@ function account_create($error = "") { global $theme; if ($error) { - $output .= "

". t("Failed to create account: $error.") ."

\n"; + $output .= "

". t("Failed to create account") .": ". check_output($error) .".

\n"; watchdog("message", "failed to create account: $error."); } else { @@ -47,8 +47,19 @@ function account_create($error = "") { function account_session_start($userid, $passwd) { global $user; if ($userid && $passwd) $user = new User($userid, $passwd); - if ($user->id) session_register("user"); - watchdog("message", ($user->id ? "session opened for user '$user->userid'" : "failed login for user '$userid'")); + if ($user->id) { + if ($rule = user_ban($user->userid, "username")) { + watchdog("message", "failed to login for '$user->userid': banned by $rule->type rule '$rule->mask'"); + } + else if ($rule = user_ban($user->last_host, "hostname")) { + watchdog("message", "failed to login for '$user->userid': banned by $rule->type rule '$rule->mask'"); + } + else { + session_register("user"); + watchdog("message", "session opened for '$user->userid'"); + } + } + else watchdog("message", "failed to login for '$userid': invalid username - password combination"); } function account_session_close() { @@ -283,20 +294,18 @@ function account_user($uname) { } function account_validate($user) { - global $type2index; - // Verify username and e-mail address: - if (empty($user[real_email]) || (!eregi("^[_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,3}$", $user[real_email]))) $error = t("the specified e-mail address is not valid"); - if (empty($user[userid]) || (ereg("[^a-zA-Z0-9_-]", $user[userid]))) $error = t("the specified username is not valid"); - if (strlen($user[userid]) > 15) $error = t("the specified username is too long: it must be less than 15 characters"); + if (empty($user[real_email]) || (!eregi("^[_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,3}$", $user[real_email]))) $error = t("the e-mail address '$user[real_email]' is not valid"); + if (empty($user[userid]) || (ereg("[^a-zA-Z0-9_-]", $user[userid]))) $error = t("the username '$user[userid]' is not valid"); + if (strlen($user[userid]) > 15) $error = t("the username '$user[userid]' is too long: it must be less than 15 characters"); // Check to see whether the username or e-mail address are banned: - if ($ban = ban_match($user[userid], $type2index[usernames])) $error = t("the specified username is banned") .": $ban->reason"; - if ($ban = ban_match($user[real_email], $type2index[addresses])) $error = t("the specified e-mail address is banned") .": $ban->reason"; + if ($ban = user_ban($user[userid], "username")) $error = t("the username '$user[userid]' is banned") .": $ban->reason"; + if ($ban = user_ban($user[real_email], "e-mail address")) $error = t("the e-mail address '$user[real_email]' is banned") .": $ban->reason"; // Verify whether username and e-mail address are unique: - if (db_num_rows(db_query("SELECT userid FROM users WHERE LOWER(userid) = LOWER('$user[userid]')")) > 0) $error = t("the specified username is already taken"); - if (db_num_rows(db_query("SELECT real_email FROM users WHERE LOWER(real_email) = LOWER('$user[real_email]')")) > 0) $error = t("the specified e-mail address is already in use by another account"); + if (db_num_rows(db_query("SELECT userid FROM users WHERE LOWER(userid) = LOWER('$user[userid]')")) > 0) $error = t("the username '$user[userid]' is already taken"); + if (db_num_rows(db_query("SELECT real_email FROM users WHERE LOWER(real_email) = LOWER('$user[real_email]')")) > 0) $error = t("the e-mail address '$user[real_email]' is already in use by another account"); return $error; } diff --git a/admin.php b/admin.php index acf8986b5a1..9a430806302 100644 --- a/admin.php +++ b/admin.php @@ -5,6 +5,10 @@ include_once "includes/common.inc"; // validate user access: if (!user_access($user)) exit(); +function status($message) { + if ($message) return "Status: $message
\n"; +} + function admin_page($mod) { global $repository, $site_name, $menu, $modules, $user; diff --git a/includes/ban.inc b/includes/ban.inc deleted file mode 100644 index 98f39be6d6c..00000000000 --- a/includes/ban.inc +++ /dev/null @@ -1,54 +0,0 @@ - 0x01, - "profanity" => 0x02, - "hostnames" => 0x03, - "usernames" => 0x04); - -$index2type = array(0x01 => "addresses", - 0x02 => "profanity", - 0x03 => "hostnames", - 0x04 => "usernames"); - -function ban_match($mask, $category) { - // Perform query: - $result = db_query("SELECT * FROM bans WHERE type = '$category' AND LOWER('$mask') LIKE LOWER(mask)"); - - // Return result: - return db_fetch_object($result); -} - -// TODO --> $message by reference -function ban_add($mask, $category, $reason, $message = 0) { - global $index2type; - - if (empty($mask)) { - $message = "failed: empty banmasks are not allowed.

\n"; - } - else if ($ban = db_fetch_object(db_query("SELECT * FROM bans WHERE type = '$category' AND '$mask' LIKE mask"))) { - $message = "failed: ban is already matched by '$ban->mask'.

\n"; - } - else { - $result = db_query("INSERT INTO bans (mask, type, reason, timestamp) VALUES ('$mask', '$category', '$reason', '". time() ."')"); - $message = "added new ban with mask '$mask'.

\n"; - - // Add log entry: - watchdog("message", "added new ban '$mask' to category '". $index2type[$category] ."' with reason '$reason'."); - } -} - -function ban_delete($id) { - global $index2type; - - $result = db_query("SELECT * FROM bans WHERE id = '$id'"); - - if ($ban = db_fetch_object($result)) { - // Perform query: - $result = db_query("DELETE FROM bans WHERE id = '$id'"); - - // Deleted log entry: - watchdog("message", "removed ban '$ban->mask' from category '". $index2type[$ban->type] ."'."); - } -} - -?> diff --git a/includes/comment.inc b/includes/comment.inc index 57b87583b2c..b15cee23b5c 100644 --- a/includes/comment.inc +++ b/includes/comment.inc @@ -184,14 +184,12 @@ function comment_moderation($comment) { function comment_controls($threshold = 1, $mode = 3, $order = 1) { global $REQUEST_URI, $user; - $output .= "\n"; $output .= "

\n"; $output .= comment_mode(($user->id ? $user->mode : $mode)); $output .= comment_order(($user->id ? $user->sort : $order)); $output .= comment_threshold(($user->id ? $user->threshold : $threshold)); $output .= "\n"; $output .= "\n"; - $output .= "
\n"; return $output; } @@ -289,7 +287,7 @@ function comment_render($lid, $cid) { if ($user->id) { // Comment control: - $theme->controls($threshold, $mode, $order); + $theme->box(t("Comment control"), "
". comment_controls($threshold, $mode, $order) ."
"); // Print moderation form: print "
\n"; diff --git a/includes/node.inc b/includes/node.inc index 8afed3ecce7..d67eb470d1c 100644 --- a/includes/node.inc +++ b/includes/node.inc @@ -36,6 +36,8 @@ function node_save($node) { $rows = array(nid, pid, lid, log, type, title, score, votes, author, status, timestamp); if ($node[nid] > 0) { + $n = node_get_object("nid", $node[nid]); + $u1 = array(); $u2 = array(); @@ -49,10 +51,10 @@ function node_save($node) { } if ($u1 = implode(", ", $u1)) db_query("UPDATE node SET $u1 WHERE nid = '$node[nid]'"); - if ($u2 = implode(", ", $u2)) db_query("UPDATE $node[type] SET $u2 WHERE nid = '$node[nid]'"); - if (($node[pid]) && ($node[status] == $status[posted])) db_query("UPDATE node SET status = '$status[expired]' WHERE nid = '$node[pid]'"); + if ($u2 = implode(", ", $u2)) db_query("UPDATE $n->type SET $u2 WHERE nid = '$node[nid]'"); + if ($n->pid && ($node[status] == $status[posted])) db_query("UPDATE node SET status = '$status[expired]' WHERE nid = '$node[pid]'"); - watchdog("message", "node: modified '$node[title]'"); + watchdog("message", "node: modified '$n->title'"); } else { $duplicate = node_get_object("title", $node[title]); diff --git a/includes/user.inc b/includes/user.inc index 66a015e4fc7..09b43410285 100644 --- a/includes/user.inc +++ b/includes/user.inc @@ -95,4 +95,9 @@ function user_access($account, $section = 0) { else return ($account->access || $account->id == 1); } +function user_ban($mask, $type) { + $result = db_query("SELECT * FROM access WHERE type = '$type' AND '$mask' REGEXP mask"); + return db_fetch_object($result); +} + ?> \ No newline at end of file diff --git a/modules/account.module b/modules/account.module index 71671cbd331..5fd8f85adfb 100644 --- a/modules/account.module +++ b/modules/account.module @@ -6,9 +6,33 @@ $module = array("help" => "account_help", function account_help() { ?> -

The account-module is responsible for maintaining the user database. It automatically handles tasks like registration, authentication, access rights, password retrieval, user settings and much more.

+

The account-module is responsible for maintaining the user database. It automatically handles tasks like registration, authentication, access control, password retrieval, user settings and much more.

The required administration can be accomplished through the "account" interface of the administration section. From here administrators can get a quick overview of all registered users and view/edit specific accounts using the links provided. Some useful operations include blocking specific accounts (e.g. a troublesome user) and giving/taking administration permissions. Note that you should only give these permissions to people you trust!

Check the documentation page for detailed information about user management.

+

Regular expressions

+

A regular expression (or regexp, or pattern) is a text string that describes some (mathematical) set of strings. A regexp R "matches" a string S if S is in the set of strings described by R.

+

Regular expressions are very powerful but often get complicated and nothing in this write-up can change that. +

A complete explanation of regular expressions is beyond the scope of this help system. A regular expression may use any of the following special characters/constructs:

+ + + + + + + + + + + + +
^Matches the beginning of a string.
$Matches the end of a string.
.Matches any character (including newline). For example the regular expression a.c would match the strings abc, adb, axb, but not axxc.
a*Matches any sequence of zero or more a characters.
a+Matches any sequence of one or more a characters.
a?Matches either zero or one a character.
ab|cdMatches either of the sequences "ab" or "cd".
(abc)*Matches zero or more instances of the sequence abc.
[abc]Matches any one of the characters between the brackets: a, b or c. Ranges of characters can specified by using a hyphen. For example, the regular expression [0-9] means match any digit. Multiple ranges can be specified as well. The regular expression [A-Za-z] means match any upper or lower case letter. To match any character except those in the range, the complement range, use the caret as the first character after the opening bracket. For example, the expression [^269A-Z] will match any characters except 2, 6, 9, and upper case letters.
{num}Matches the preceding element num times.
{min, max}Matches the preceding element at least min times, but not more than max times.
+

Examples:

+ + + + + +
appleMatches any string that has the text "apple" in it.
^apple$Matches the exact string "apple".
^appleMatches any string that starts with "apple".
domain\.com$Matches any string that ends with "@domain.com". Note that you have to escape the dot in domain.com.
mask'" : "did not match any of the existing access rules") ."."; +} + +function account_ac() { + $access = array("e-mail address", "hostname", "username"); + + $result = db_query("SELECT * FROM access"); + + foreach ($access as $value) $type .= " \n"; + + $output .= "\n"; + $output .= "\n"; + $output .= " \n"; + while ($rule = db_fetch_object($result)) { + $output .= " \n"; + } + $output .= " \n"; + $output .= " \n"; + $output .= "
masktypereasonoparations
$rule->mask$rule->type". check_output($rule->reason) ."id\">delete rule
Use regular expressions (regexs) to specify the mask pattern.
\n"; + $output .= "

\n"; + $output .= "\n"; + $output .= " \n"; + $output .= " \n"; + $output .= "
check access rules
\n"; + $output .= "
\n"; + + return $output; +} + +function account_overview() { $result = db_query("SELECT id, userid, last_access FROM users ORDER BY last_access DESC LIMIT 50"); $output .= "\n"; - $output .= " \n"; + $output .= " \n"; while ($account = db_fetch_object($result)) { - $output .= " \n"; + $output .= " \n"; } $output .= "
usernamelast accessoperations
usernamelast accessoperations
". format_username($account->userid) ."". format_date($account->last_access) ."userid\">viewuserid\">edituserid\">delete
". format_username($account->userid) ."". format_date($account->last_access) ."userid\">view accountuserid\">edit account
\n"; - print $output; + return $output; } function account_access($account) { @@ -80,7 +142,7 @@ function account_delete($name) { db_query("DELETE FROM users WHERE id = '$account->id'"); } else { - print "

Failed to delete account '". format_username($name) ."': the account must be blocked first.

"; + return "failed to delete account '". format_username($name) ."': the account must be blocked first."; } } @@ -126,7 +188,7 @@ function account_edit($name) { $output .= "\n"; $output .= "\n"; $output .= "\n"; - print "$output"; + return $output; } } @@ -158,41 +220,56 @@ function account_view($name) { $output .= " userid\">\n"; $output .= "\n"; $output .= "\n"; - print "$output"; + return $output; } } function account_admin() { - global $op, $edit, $order, $name; + global $op, $edit, $id, $order, $name; - print "overview | search account | help
\n"; + print " access control | search account | overview | help
\n"; switch ($op) { + case "access": + print account_ac(); + break; + case "Add rule": + print status(account_ac_add($edit)); + print account_ac(); + break; + case "Check": + print status(account_ac_check($edit)); + print account_ac(); + break; + case "delete rule": + print status(account_ac_del($id)); + print account_ac(); + break; case "Delete account": case "delete": - account_delete(check_input($name)); - account_display(); + print status(account_delete(check_input($name))); + print account_overview(); break; case "Edit account": case "edit": - account_edit(check_input($name)); + print account_edit(check_input($name)); break; case "help": - account_help(); + print account_help(); break; case "search": - account_search(); + print account_search(); break; case "View account": case "view": - account_view($name); + print account_view($name); break; case "Save account": - account_edit_save(check_input($name), $edit); - account_view(check_input($name)); + print status(account_edit_save(check_input($name), $edit)); + print account_view(check_input($name)); break; default: - account_display(); + print account_overview(); } } diff --git a/modules/ban.module b/modules/ban.module deleted file mode 100644 index 3d1d8a64f2a..00000000000 --- a/modules/ban.module +++ /dev/null @@ -1,143 +0,0 @@ - "ban_help", - "admin" => "ban_admin"); - -include_once "includes/ban.inc"; - - -function ban_help() { - ?> -

The ban module keeps a list of bans in four categories:

- -

The ban module allows you to use a flexible wild-card ban system. This means you can block all email addresses from a certain domain name, block every username starting with "guest", etc. To do this, use the following wild-card characters:

- -

Examples:

- - \n"; - $output .= " \n"; - $output .= " \n"; - $output .= "
\n"; - $output .= " \n"; - $output .= " \n"; - $output .= "
\n"; - $output .= " \n"; - $output .= " \n"; - $output .= " maskreasonoperations\n"; - while ($ban = db_fetch_object($result)) { - $output .= " $ban->mask$ban->reasonid\">delete\n"; - } - $output .= " %: matches any number of characters, even zero characters.
_: matches exactly one character.
\n"; - $output .= "\n"; - - print $output; -} - -function ban_admin_add() { - global $type2index; - - $output .= "

Add new ban:

\n"; - $output .= "
\n"; - - $output .= "Banmask:
\n"; - $output .= "

\n"; - - $output .= "Type:
\n"; - for (reset($type2index); $cur = current($type2index); next($type2index)) $options .= "\n"; - $output .= "

\n"; - - $output .= "Reason:
\n"; - $output .= "

\n"; - - $output .= "
\n"; - $output .= "

\n"; - - print $output; -} - -function ban_check($mask, $category) { - $ban = ban_match($mask, $category); - $output .= "". ($ban ? "Matched ban '$ban->mask' with reason: $ban->reason.

\n" : "No matching bans for '$mask'.

\n") .""; - print $output; -} - -function ban_admin_check() { - global $type2index; - - $output .= "

Ban check:

\n"; - $output .= "
\n"; - - $output .= "Banmask:
\n"; - $output .= "

\n"; - - $output .= "Type:
\n"; - for (reset($type2index); $cur = current($type2index); next($type2index)) $options .= "\n"; - $output .= "

\n"; - - $output .= "
\n"; - $output .= "

\n"; - - print $output; -} - -function ban_admin() { - global $op, $id, $mask, $category, $reason; - - print "add ban | check ban | overview | help
\n"; - - switch ($op) { - case "Add ban": - ban_admin_new(check_input($mask), check_input($category), check_input($reason)); - ban_display(check_input($category)); - break; - case "Check ban": - ban_check(check_input($mask), check_input($category)); - break; - case "add": - ban_admin_add(); - break; - case "help": - ban_help(); - break; - case "check": - ban_admin_check(); - break; - case "delete": - ban_delete(check_input($id)); - default: - ban_display(check_input($category)); - } -} - -?> diff --git a/modules/book.module b/modules/book.module index 04b0eb28025..d5e5c0f9353 100644 --- a/modules/book.module +++ b/modules/book.module @@ -154,10 +154,6 @@ function book_save($edit) { node_save(array_diff(array_merge($edit, array(nid => $edit[nid], type => "book")), array(userid => $edit[userid]))); } -function book_delete($id) { - return ($node = node_del("nid", $id) ? "book page has been deleted" : "failed to delete book page: change status to 'dumped' first"); -} - function book_tree($parent = "") { global $PHP_SELF, $status; @@ -166,7 +162,7 @@ function book_tree($parent = "") { $output .= "