Index: includes/actions.inc
===================================================================
RCS file: includes/actions.inc
diff -N includes/actions.inc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ includes/actions.inc 12 Jun 2007 20:06:56 -0000
@@ -0,0 +1,218 @@
+ variable_get('actions_max_stack', 35)) {
+ watchdog('actions', t('Stack overflow: too many calls to actions_do(). Aborting to prevent infinite recursion.'), WATCHDOG_ERROR);
+ return;
+ }
+ $actions = array();
+ $available_actions = actions_list();
+ $result = array();
+ if (is_array($action_ids)) {
+ $where = '';
+ foreach ($action_ids as $action_id) {
+ if (is_numeric($action_id)) {
+ $where .= 'OR aid = ' . $action_id . ' ';
+ }
+ elseif (isset($available_actions[$action_id])) {
+ $actions[$action_id] = $available_actions[$action_id];
+ }
+ }
+
+ if ($where) { // We must go to the database to retrieve instance data.
+ // Strip off leading 'OR '.
+ $where = $where ? '(' . strstr($where, " ") . ')' : '';
+ $result_db = db_query("SELECT * FROM {actions} WHERE $where");
+ while ($data = db_fetch_object($result_db)) {
+ $action_id = $data->action_id;
+ $actions[$action_id] = $data->params ? unserialize($data->params) : array();
+ $actions[$action_id]['function'] = $data->func;
+ $actions[$action_id]['type'] = $data->type;
+ }
+ }
+
+ // Fire actions, in no particular order.
+ foreach ($actions as $action_id => $params) {
+ if (is_numeric($action_id)) { // Configurable actions need parameters.
+ $function = $params['function'];
+ $context = array_merge($context, $params);
+ $result[$action_id] = $function('do', $context, $object, $a3, $a4);
+ }
+ else { // Singleton action; $action_id is the function name.
+ $result[$action_id] = $action_id($context, $object, $a3, $a4);
+ }
+ }
+ }
+ else { // Optimized execution of single action.
+ if (is_numeric($action_ids)) { // Configurable action; retrieve stored parameters.
+ $data = db_fetch_object(db_query("SELECT * FROM {actions} WHERE aid = %d", $action_ids));
+ $function = $data->func;
+ $context = array_merge($context, unserialize($data->params));
+ $result[$action_ids] = $function($context, $object, $a3, $a4);
+ }
+ else { // Singleton action; $action_ids is the function name.
+ $result[$action_ids] = $action_ids($context, $object, $a4, $a4);
+ }
+ }
+ return $result;
+}
+
+
+/**
+ * Discover all action functions by invoking hook_action_info().
+ *
+ * mymodule_action_info() {
+ * return array(
+ * 'mymodule_functiondescription_action' => array(
+ * 'type' => 'node',
+ * 'description' => t('Save node'),
+ * 'configurable' => FALSE,
+ * 'hooks' => array(
+ * 'nodeapi' => array('delete','insert','update', 'view'),
+ * 'comment' => array('delete','insert','update', 'view'),
+ * )
+ * )
+ * );
+ * }
+ *
+ * The description is used in presenting possible actions to the user for
+ * configuration. The type is used to present these actions in a logical
+ * grouping and to denote context. Some types are 'node', 'user', 'comment',
+ * and 'system'. If an action is configurable it will provide form,
+ * validation and submission functions. The hooks the action supports
+ * are declared in the 'hooks' array.
+ *
+ * @return
+ * An associative array keyed on function name. The value of each key is
+ * an array containing information about the action, such as type of
+ * action and description of the action, e.g.,
+ *
+ * $actions['actions_node_publish'] = ('description' => 'Publish a node' ... )
+ *
+*/
+function actions_list() {
+ static $actions;
+ if (isset($actions)) {
+ return $actions;
+ }
+
+ $actions = module_invoke_all('action_info');
+ return $actions;
+}
+
+/**
+ * Retrieve all action instances from the database.
+ * Compare with actions_list() which gathers actions from
+ * the PHP function namespace. The two are synchronized
+ * by visiting /admin/build/actions (when actions.module is
+ * enabled) which runs actions_synchronize().
+ *
+ * @return
+ * Associative array keyed by action ID. Each value is
+ * an associative array with keys 'function', 'description',
+ * and 'type'.
+ */
+function actions_get_all_actions() {
+ $actions = array();
+ $result = db_query("SELECT * FROM {actions}");
+ while ($data = db_fetch_object($result)) {
+ $actions[$data->aid] = array(
+ 'function' => $data->func,
+ 'description' => $data->description,
+ 'type' => $data->type,
+ 'configurable' => $data->params ? TRUE : FALSE,
+ );
+ }
+ return $actions;
+}
+
+/**
+ * Create an associative array keyed by md5 hashes of function names.
+ * Hashes are used to prevent actual function names from going out into
+ * HTML forms and coming back.
+ *
+ * @param $actions
+ * An associative array with function names as keys and associative
+ * arrays with keys 'description', 'type', etc. as values. Generally
+ * the output of actions_list() or actions_get_all_actions() is given
+ * as input to this function.
+ *
+ * @return
+ * An associative array keyed on md5 hash of function name. The value of
+ * each key is an associative array of function, description, and type
+ * for the action.
+ */
+function actions_actions_map($actions) {
+ $actions_map = array();
+ foreach ($actions as $func => $array) {
+ $key = md5($func);
+ $actions_map[$key]['function'] = isset($array['function']) ? $array['function'] : $func;
+ $actions_map[$key]['description'] = $array['description'];
+ $actions_map[$key]['type'] = $array['type'];
+ $actions_map[$key]['configurable'] = $array['configurable'];
+ }
+ return $actions_map;
+}
+
+/**
+ * Given an md5 hash of a function name, return the function name.
+ * Faster than actions_actions_map() when you only need the function name.
+ *
+ * @param $hash
+ * MD5 hash of a function name
+ *
+ * @return
+ * Function name
+ */
+function actions_function_lookup($hash) {
+ $actions_list = actions_list();
+ foreach ($actions_list as $function => $array) {
+ if (md5($function) == $hash) {
+ return $function;
+ }
+ }
+
+ // Must be an instance; must check database.
+ $result = db_query("SELECT aid FROM {actions} WHERE params != ''");
+ while ($data = db_fetch_object($result)) {
+ if (md5($data->aid) == $hash) {
+ return $data->aid;
+ }
+ }
+}
\ No newline at end of file
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.653
diff -u -u -p -r1.653 common.inc
--- includes/common.inc 11 Jun 2007 15:21:14 -0000 1.653
+++ includes/common.inc 12 Jun 2007 20:06:57 -0000
@@ -2228,6 +2228,7 @@ function _drupal_bootstrap_full() {
require_once './includes/unicode.inc';
require_once './includes/image.inc';
require_once './includes/form.inc';
+ require_once './includes/actions.inc';
// Set the Drupal custom error handler.
set_error_handler('drupal_error_handler');
// Emit the correct charset HTTP header.
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.552
diff -u -u -p -r1.552 comment.module
--- modules/comment/comment.module 11 Jun 2007 14:56:40 -0000 1.552
+++ modules/comment/comment.module 12 Jun 2007 20:06:57 -0000
@@ -2063,3 +2063,91 @@ function int2vancode($i = 0) {
function vancode2int($c = '00') {
return base_convert(substr($c, 1), 36, 10);
}
+
+/**
+ * Implementation of hook_action_info().
+ */
+function comment_action_info() {
+ return array(
+ 'comment_unpublish_action' => array(
+ 'description' => t('Unpublish comment'),
+ 'type' => 'comment',
+ 'configurable' => FALSE,
+ 'hooks' => array(
+ 'comment' => array('insert', 'update', 'view'),
+ )
+ ),
+ 'comment_unpublish_by_keyword_action' => array(
+ 'description' => t('Unpublish comment containing keyword(s)'),
+ 'type' => 'comment',
+ 'configurable' => TRUE,
+ 'hooks' => array(
+ 'comment' => array('insert', 'update'),
+ )
+ )
+ );
+}
+
+/**
+ * Drupal action to unpublish a comment.
+ *
+ * @param $context
+ * Keyed array. Must contain the id of the comment if $comment is not passed.
+ * @param $comment
+ * An optional comment object.
+ */
+function comment_unpublish_action($comment, $context = array()) {
+ if (isset($comment->cid)) {
+ $cid = $comment->cid;
+ $subject = $comment->subject;
+ }
+ else {
+ $cid = $context['cid'];
+ $subject = db_result(db_query("SELECT subject FROM {comments} WHERE cid = %d", $cid));
+ }
+ db_query('UPDATE {comments} SET status = %d WHERE cid = %d', COMMENT_PUBLISHED, $cid);
+ watchdog('action', t('Unpublished comment %subject.', array('%subject' => $subject)));
+}
+
+function comment_unpublish_by_keyword_action_form($context) {
+ if (!module_exists('taxonomy')) {
+ $form['warning'] = array(
+ '#prefix' => "
",
+ '#suffix' => '
',
+ '#value' => t('This action requires the !taxonomy_module to be enabled.', array('!taxonomy_module' => l('taxonomy module', 'admin/build/modules'))),
+ '#weight' => -8,
+ );
+ }
+ $form['keywords'] = array(
+ '#title' => t('Keywords'),
+ '#type' => 'textfield',
+ '#description' => t('The comment will be unpublished if it contains any of the keywords above. Use a comma-separated list of keywords. Example: funny, bungee jumping, "Company, Inc.".'),
+ '#default_value' => isset($context['keywords']) ? implode(',', $context['keywords']) : '',
+ );
+ return $form;
+}
+
+function comment_unpublish_by_keyword_action_submit($form, $form_state) {
+ return array('keywords' => taxonomy_explode_tags($form_state['values']['keywords']));
+}
+
+/**
+ * Implementation of a configurable Drupal action.
+ * Unpublish a comment if it contains a certain string.
+ *
+ * @param $context
+ * An array providing more information about the context of the call to this action.
+ * Unused here since this action currently only supports the insert and update ops of
+ * the comment hook, both of which provide a complete $comment object.
+ * @param $comment
+ * A comment object.
+ */
+function comment_unpublish_by_keyword_action($comment, $context) {
+ foreach ($context['keywords'] as $keyword) {
+ if (strstr($comment->comment, $keyword)) {
+ db_query('UPDATE {comments} SET status = '. COMMENT_NOT_PUBLISHED .' WHERE cid = %d', $comment->cid);
+ watchdog('action', 'Unpublished comment %subject.', array('%subject' => $comment->subject));
+ break;
+ }
+ }
+}
\ No newline at end of file
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.829
diff -u -u -p -r1.829 node.module
--- modules/node/node.module 7 Jun 2007 03:45:57 -0000 1.829
+++ modules/node/node.module 12 Jun 2007 20:06:57 -0000
@@ -613,6 +613,8 @@ function node_load($param = array(), $re
* Save a node object into the database.
*/
function node_save(&$node) {
+ // Let modules modify the node before it is saved to the database.
+ node_invoke_nodeapi($node, 'presave');
global $user;
$node->is_new = FALSE;
@@ -3100,3 +3102,198 @@ function node_forms() {
}
return $forms;
}
+
+/**
+ * Implementation of hook_action_info().
+ */
+function node_action_info() {
+ return array(
+ 'node_publish_action' => array(
+ 'type' => 'node',
+ 'description' => t('Publish node'),
+ 'configurable' => FALSE,
+ 'hooks' => array(
+ 'nodeapi' => array('presave','insert','update', 'view'),
+ 'comment' => array('delete','insert','update', 'view'),
+ ),
+ ),
+ 'node_unpublish_action' => array(
+ 'type' => 'node',
+ 'description' => t('Unpublish node'),
+ 'configurable' => FALSE,
+ 'hooks' => array(
+ 'nodeapi' => array('presave','insert','update', 'view'),
+ 'comment' => array('delete','insert','update', 'view'),
+ ),
+ ),
+ 'node_make_sticky_action' => array(
+ 'type' => 'node',
+ 'description' => t('Make node sticky'),
+ 'configurable' => FALSE,
+ 'hooks' => array(
+ 'nodeapi' => array('presave','insert','update', 'view'),
+ 'comment' => array('delete','insert','update', 'view'),
+ ),
+ ),
+ 'node_make_unsticky_action' => array(
+ 'type' => 'node',
+ 'description' => t('Make node unsticky'),
+ 'configurable' => FALSE,
+ 'hooks' => array(
+ 'nodeapi' => array('presave','insert','update', 'view'),
+ 'comment' => array('delete','insert','update', 'view'),
+ ),
+ ),
+ 'node_promote_action' => array(
+ 'type' => 'node',
+ 'description' => t('Promote node to front page'),
+ 'configurable' => FALSE,
+ 'hooks' => array(
+ 'nodeapi' => array('presave','insert','update', 'view'),
+ 'comment' => array('delete','insert','update', 'view'),
+ ),
+ ),
+ 'node_unpromote_action' => array(
+ 'type' => 'node',
+ 'description' => t('Remove post from node page'),
+ 'configurable' => FALSE,
+ 'hooks' => array(
+ 'nodeapi' => array('presave','insert','update', 'view'),
+ 'comment' => array('delete','insert','update', 'view'),
+ ),
+ ),
+ 'node_assign_owner_action' => array(
+ 'type' => 'node',
+ 'description' => t('Change the author of a node'),
+ 'configurable' => TRUE,
+ 'hooks' => array(
+ 'nodeapi' => array('presave','insert','update', 'view'),
+ 'comment' => array('delete','insert','update', 'view'),
+ ),
+ ),
+ 'node_save_action' => array(
+ 'type' => 'node',
+ 'description' => t('Save node'),
+ 'configurable' => FALSE,
+ 'hooks' => array(
+ 'nodeapi' => array('delete','insert','update', 'view'),
+ 'comment' => array('delete','insert','update', 'view'),
+ ),
+ ),
+ );
+}
+
+/**
+ * Implementation of a Drupal action.
+ * Sets the status of a node to 1, meaning published.
+ */
+function node_publish_action(&$node, $context = array()) {
+ $node->status = 1;
+ watchdog('action', t('Set @type %title to published.', array('@type' => node_get_types('name', $node), '%title' => $node->title)));
+}
+
+/**
+ * Implementation of a Drupal action.
+ * Sets the status of a node to 0, meaning unpublished.
+ */
+function node_unpublish_action(&$node, $context = array()) {
+ $node->status = 0;
+ watchdog('action', t('Set @type %title to unpublished.', array('@type' => node_get_types('name', $node), '%title' => $node->title)));
+}
+
+/**
+ * Implementation of a Drupal action.
+ * Sets the sticky-at-top-of-list property of a node to 1.
+ */
+function node_make_sticky_action(&$node, $context = array()) {
+ $node->sticky = 1;
+ watchdog('action', t('Set @type %title to sticky.', array('@type' => node_get_types('name', $node), '%title' => $node->title)));
+}
+
+/**
+ * Implementation of a Drupal action.
+ * Sets the sticky-at-top-of-list property of a node to 1.
+ */
+function node_make_unsticky_action(&$node, $context = array()) {
+ $node->sticky = 0;
+ watchdog('action', t('Set @type %title to unsticky.', array('@type' => node_get_types('name', $node), '%title' => $node->title)));
+}
+
+/**
+ * Implementation of a Drupal action.
+ * Sets the promote property of a node to 1.
+ */
+function node_promote_action($op, &$node, $context = array()) {
+ $node->promote = 1;
+ watchdog('action', t('Promoted @type %title to front page.', array('@type' => node_get_types('type', $node), '%title' => $node->title)));
+}
+
+/**
+ * Implementation of a Drupal action.
+ * Sets the promote property of a node to 0.
+ */
+function node_unpromote_action($op, &$node, $context = array()) {
+ $node->promote = 1;
+ watchdog('action', t('Removed @type %title from front page.', array('@type' => node_get_types('type', $node), '%title' => $node->title)));
+}
+
+/**
+ * Implementation of a configurable Drupal action.
+ * Assigns ownership of a node to a user.
+ */
+function node_assign_owner_action(&$node, $context = array()) {
+ $uid = db_result(db_query("SELECT uid FROM {users} WHERE name = '%s'", $context['owner_name']));
+ $node->uid = $uid;
+ watchdog('action', t('Changed owner of @type %title to uid %name.', array('@type' => node_get_types('type', $node), '%title' => $node->title, '%name' => $context['owner_name'])));
+}
+
+function node_assign_owner_action_form($context) {
+ $description = t('The username of the user to which you would like to assign ownership.');
+ $count = db_result(db_query("SELECT COUNT(*) FROM {users}"));
+ // Use dropdown for fewer than 200 users; textbox for more than that.
+ if (intval($count) < 200) {
+ $options = array();
+ $result = db_query("SELECT uid, name FROM {users} WHERE uid > 0 ORDER BY name");
+ while ($data = db_fetch_object($result)) {
+ $options[$data->name] = $data->name;
+ }
+ $form['owner_name'] = array(
+ '#type' => 'select',
+ '#title' => t('Username'),
+ '#default_value' => isset($context['owner_name']) ? $context['owner_name'] : '',
+ '#options' => $options,
+ '#description' => $description,
+ );
+ }
+ else {
+ $form['owner_name'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Username'),
+ '#default_value' => isset($context['owner_name']) ? $context['owner_name'] : '',
+ '#size' => '6',
+ '#maxlength' => '7',
+ '#description' => $description,
+ );
+ }
+ return $form;
+}
+
+function node_assign_owner_action_validate($form_id, $form_values) {
+ $count = db_result(db_query("SELECT COUNT(*) FROM {users} WHERE name = '%s'", $context['owner_name']));
+ if (intval($count) != 1) {
+ form_set_error('owner_name', t('Please enter a valid username.'));
+ }
+}
+
+function node_assign_owner_action_submit($form_id, $form_values) {
+ return array('owner_name' => $form_values['owner_name']);
+}
+
+/**
+ * Implementation of a configurable Drupal action.
+ * Saves a node.
+ */
+function node_save_action($node) {
+ node_save($node);
+ watchdog('action', t('Saved @type %title', array('@type' => node_get_types('type', $node), '%title' => $node->title)));
+}
\ No newline at end of file
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.491
diff -u -u -p -r1.491 system.module
--- modules/system/system.module 8 Jun 2007 12:51:59 -0000 1.491
+++ modules/system/system.module 12 Jun 2007 20:06:57 -0000
@@ -2718,3 +2718,190 @@ function system_batch_page() {
print theme('page', $output, FALSE, FALSE);
}
}
+
+/**
+ * Implementation of hook_action_info().
+ */
+function system_action_info() {
+ return array(
+ 'system_message_action' => array(
+ 'type' => 'system',
+ 'description' => t('Display a message to the user'),
+ 'configurable' => TRUE,
+ 'hooks' => array(
+ 'nodeapi' => array('view', 'insert', 'update', 'delete'),
+ 'comment' => array('view', 'insert', 'update', 'delete'),
+ 'user' => array('view', 'insert', 'update', 'delete', 'login'),
+ ),
+ ),
+ 'system_send_email_action' => array(
+ 'description' => t('Send e-mail'),
+ 'type' => 'system',
+ 'configurable' => TRUE,
+ 'hooks' => array(
+ 'nodeapi' => array('view', 'insert', 'update', 'delete'),
+ 'comment' => array('view', 'insert', 'update', 'delete'),
+ 'user' => array('view', 'insert', 'update', 'delete', 'login'),
+ )
+ )
+ );
+}
+
+/**
+ * Implementation of a configurable Drupal action.
+ * Sends an email.
+ */
+function system_send_email_action($object, $context) {
+ switch($context['hook']) {
+ case 'node':
+ $node = $object;
+ break;
+ // The comment hook also provides the node, in context.
+ case 'comment':
+ $node = $context['node'];
+ case 'user':
+ $user = $object;
+ break;
+ }
+
+ // Note this is the user who owns the node, not global $user.
+ if (!isset($user)) {
+ $user = user_load(array('uid' => $node->uid));
+ }
+ $from = variable_get('site_mail', ini_get('sendmail_from'));
+ $subject = $context['subject'];
+ $message = $context['message'];
+ if ($context['recipient'] == '%author') {
+ $recipient = $user->mail;
+ } else {
+ $recipient = $context['recipient'];
+ }
+ $variables['%site_name'] = variable_get('site_name', 'Drupal');
+ $variables['%username'] = $user->name;
+
+ // Node-based variable translation is only available if we have a node.
+ if (isset($node) && is_object($node)) {
+ $variables = array_merge($variables, array(
+ '%username' => check_plain($user->name),
+ '%uid' => $node->uid,
+ '%node_url' => url('node/' . $node->nid, NULL, NULL, TRUE),
+ '%node_type' => check_plain($node->type),
+ '%title' => filter_xss($node->title),
+ '%teaser' => filter_xss($node->teaser),
+ '%body' => filter_xss($node->body)
+ )
+ );
+
+ $subject = strtr($subject, $variables);
+ $subject = str_replace(array("\r", "\n"), '', $subject);
+ $message = strtr($message, $variables);
+ }
+ if (drupal_mail('action_send_email', $recipient, $subject, $message, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from" )) {
+ watchdog('action', t('Sent email to %recipient', array('%recipient' => $recipient)));
+ }
+ else {
+ watchdog('error', t('Unable to send email to %recipient', array('%recipient' => $recipient)));
+ }
+}
+
+function system_send_email_action_form($context) {
+ // Return a form definition for the configuration form.
+ // Set default values for form.
+ if (!isset($context['recipient'])) $context['recipient'] = '';
+ if (!isset($context['subject'])) $context['subject'] = '';
+ if (!isset($context['message'])) $context['message'] = '';
+
+ $form['recipient'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Recipient'),
+ '#default_value' => $context['recipient'],
+ '#size' => '20',
+ '#maxlength' => '254',
+ '#description' => t('The email address to which the message should be sent OR enter %author if you would like to send an e-mail to the original author of the post.', array('%author' => t('%author'))),
+ );
+ $form['subject'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Subject'),
+ '#default_value' => $context['subject'],
+ '#size' => '20',
+ '#maxlength' => '254',
+ '#description' => t('The subject of the message.'),
+ );
+ $form['message'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Message'),
+ '#default_value' => $context['message'],
+ '#cols' => '80',
+ '#rows' => '20',
+ '#description' => t('The message that should be sent. You may include the following variables: %site_name, %username, %node_url, %node_type, %title, %teaser, %body. Not all variables will be available in all contexts.'),
+ );
+ return $form;
+}
+
+function system_send_email_action_validate($form, $form_state) {
+ $form_values = $form_state['values'];
+ // Validate the configuration form.
+ if (!valid_email_address($form_values['recipient']) && $form_values['recipient'] != t('%author')) {
+ form_set_error('recipient', t('Please enter a valid email address or %author.', array('%author' => theme('placeholder', '%author'))));
+ }
+}
+
+function system_send_email_action_submit($form, $form_state) {
+ $form_values = $form_state['values'];
+ // Process the HTML form to store configuration. The keyed array that
+ // we return will be serialized to the database.
+ $params = array(
+ 'recipient' => $form_values['recipient'],
+ 'subject' => $form_values['subject'],
+ 'message' => $form_values['message']);
+ return $params;
+}
+
+function system_message_action_form($context) {
+ $form['message'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Message'),
+ '#default_value' => isset($context['message']) ? $context['message'] : '',
+ '#required' => TRUE,
+ '#rows' => '8',
+ '#description' => t('The message to be displayed to the current user. You may include the following variables: %site_name, %username, %node_url, %node_type, %title, %teaser, %body.'),
+ );
+ return $form;
+}
+
+function system_message_action_submit($form, $form_state) {
+ return array('message' => $form_state['values']['message']);
+}
+
+/**
+ * Implementation of a configurable Drupal action.
+ * Sends a configurable message to the current user's screen.
+ */
+function system_message_action(&$object, $context = array()) {
+ switch($context['hook']) {
+ case 'nodeapi':
+ $node = &$object;
+ break;
+ // The comment hook gives us the nid of the node.
+ case 'comment':
+ $node = node_load($object['nid']);
+ }
+ global $user;
+ $variables = array(
+ '%site_name' => variable_get('site_name', 'drupal'),
+ '%username' => $user->name ? $user->name : variable_get('anonymous', t('Anonymous')),
+ );
+
+ if (isset($node) && is_object($node)) {
+ $variables += array(
+ '%uid' => $node->uid,
+ '%node_url' => url('node/' . $node->nid, NULL, NULL, TRUE),
+ '%node_type' => check_plain($node->type),
+ '%title' => filter_xss($node->title),
+ '%teaser' => filter_xss($node->teaser),
+ '%body' => filter_xss($node->body),
+ );
+ }
+ $context['message'] = strtr($context['message'], $variables);
+ drupal_set_message($context['message']);
+}
\ No newline at end of file
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.796
diff -u -u -p -r1.796 user.module
--- modules/user/user.module 11 Jun 2007 15:27:52 -0000 1.796
+++ modules/user/user.module 12 Jun 2007 20:06:57 -0000
@@ -3185,3 +3185,60 @@ function _user_password_dynamic_validati
$complete = TRUE;
}
}
+
+/**
+ * Implementation of hook_action_info().
+ */
+function user_action_info() {
+ return array(
+ 'user_block_user_action' => array(
+ 'description' => t('Block current user'),
+ 'type' => 'user',
+ 'configurable' => FALSE,
+ 'hooks' => array(
+ 'user' => array('view', 'insert', 'update', 'delete', 'login', 'logout'),
+ 'nodeapi' => array('presave', 'delete','insert','update','view'),
+ 'comment' => array('view', 'insert', 'update', 'delete'),
+ ),
+ ),
+ 'user_block_ip_action' => array(
+ 'description' => t('Ban IP address of current user'),
+ 'type' => 'user',
+ 'configurable' => FALSE,
+ 'hooks' => array(
+ 'user' => array('view', 'insert', 'update', 'delete', 'login', 'logout'),
+ 'nodeapi' => array('presave', 'delete','insert','update','view'),
+ 'comment' => array('view', 'insert', 'update', 'delete'),
+ )
+ )
+ );
+}
+
+/**
+ * Implementation of a Drupal action.
+ * Blocks the current user.
+ */
+function user_block_user_action(&$object, $context = array()) {
+ if (isset($object->uid)) {
+ $uid = $object->uid;
+ }
+ elseif (isset($context['uid'])) {
+ $uid = $context['uid'];
+ }
+ else {
+ global $user;
+ $uid = $user->uid;
+ }
+ db_query("UPDATE {users} SET status = 0 WHERE uid = %d", $uid);
+ sess_destroy_uid($uid);
+ watchdog('action', t('Blocked user %name.', array('%name' => check_plain($user->name))));
+}
+
+/**
+ * Implementation of a Drupal action.
+ * Adds an access rule that blocks the user's IP address.
+ */
+function user_block_ip_action() {
+ db_query("INSERT INTO {access} (mask, type, status) VALUES ('%s', '%s', %d)", $_SERVER['REMOTE_ADDR'], 'host', 0);
+ watchdog('action', t('Banned IP %ip', array('%ip' => $_SERVER['REMOTE_ADDR'])));
+}
\ No newline at end of file