Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.774
diff -u -p -r1.774 comment.module
--- modules/comment/comment.module	22 Sep 2009 07:36:57 -0000	1.774
+++ modules/comment/comment.module	23 Sep 2009 17:08:10 -0000
@@ -1479,7 +1479,9 @@ class CommentController extends DrupalDe
     $this->query->addField('n', 'type', 'node_type');
     $this->query->innerJoin('users', 'u', 'base.uid = u.uid');
     $this->query->addField('u', 'name', 'registered_name');
-    $this->query->fields('u', array( 'uid', 'signature', 'picture', 'data', 'status'));
+    // @todo {user}.status overwrites {comment}.status.
+    $this->query->addField('u', 'status', 'user_status');
+    $this->query->fields('u', array('uid', 'signature', 'picture', 'data'));
   }
 
   protected function attachLoad(&$comments) {
@@ -1623,7 +1625,7 @@ function comment_form($form, &$form_stat
   $node = node_load($comment->nid);
 
   if (!$user->uid && variable_get('comment_anonymous_' . $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT) != COMMENT_ANONYMOUS_MAYNOT_CONTACT) {
-    $form_state['#attached']['js'][] = drupal_get_path('module', 'comment') . '/comment.js';
+    $form['#attached']['js'][] = drupal_get_path('module', 'comment') . '/comment.js';
   }
 
   $comment = (array) $comment;
@@ -1650,11 +1652,11 @@ function comment_form($form, &$form_stat
         $author = $comment->registered_name;
       }
 
-      if (!empty($comment->status)) {
+      if (isset($comment->status)) {
         $status = $comment->status;
       }
       else {
-        $status = 0;
+        $status = COMMENT_NOT_PUBLISHED;
       }
 
       if (!empty($comment->date)) {
@@ -1727,8 +1729,8 @@ function comment_form($form, &$form_stat
         '#type' => 'radios',
         '#parents' => array('status'),
         '#title' => t('Status'),
-        '#default_value' =>  $status,
-        '#options' => array(t('Not published'), t('Published')),
+        '#default_value' => $status,
+        '#options' => array(COMMENT_NOT_PUBLISHED => t('Not published'), COMMENT_PUBLISHED => t('Published')),
         '#weight' => -1,
       );
     }
@@ -2306,41 +2308,53 @@ function vancode2int($c = '00') {
 function comment_action_info() {
   return array(
     'comment_unpublish_action' => array(
-      'label' => t('Unpublish comment'),
       'type' => 'comment',
+      'label' => t('Unpublish comment'),
       'configurable' => FALSE,
-      'triggers' => array('comment_insert', 'comment_update'),
+      'behavior' => array(
+        'before' => 'comment_save_action',
+      ),
+      'triggers' => array('comment_presave', 'comment_insert', 'comment_update'),
     ),
     'comment_unpublish_by_keyword_action' => array(
-      'label' => t('Unpublish comment containing keyword(s)'),
       'type' => 'comment',
+      'label' => t('Unpublish comment containing keyword(s)'),
       'configurable' => TRUE,
+      'behavior' => array(
+        'before' => 'comment_save_action',
+      ),
+      'triggers' => array('comment_presave', 'comment_insert', 'comment_update'),
+    ),
+    'comment_save_action' => array(
+      'type' => 'comment',
+      'label' => t('Save comment'),
+      'configurable' => FALSE,
       'triggers' => array('comment_insert', 'comment_update'),
-    )
+    ),
   );
 }
 
 /**
- * Drupal action to unpublish a comment.
+ * 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.
+ * @param $context
+ *   Keyed array. Must contain the id of the comment if $comment is not passed.
  */
 function comment_unpublish_action($comment, $context = array()) {
-  if (isset($comment->cid)) {
-    $cid = $comment->cid;
+  if (isset($comment->comment)) {
     $subject = $comment->subject;
+    $comment->status = COMMENT_NOT_PUBLISHED;
   }
   else {
     $cid = $context['cid'];
     $subject = db_query('SELECT subject FROM {comment} WHERE cid = :cid', array(':cid', $cid))->fetchField();
+    db_update('comment')
+      ->fields(array('status' => COMMENT_NOT_PUBLISHED))
+      ->condition('cid', $cid)
+      ->execute();
   }
-  db_update('comment')
-    ->fields(array('status' => COMMENT_NOT_PUBLISHED))
-    ->condition('cid', $cid)
-    ->execute();
   watchdog('action', 'Unpublished comment %subject.', array('%subject' => $subject));
 }
 
@@ -2372,20 +2386,15 @@ function comment_unpublish_by_keyword_ac
  *
  * 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.
+ * @param $context
+ *   An array providing more information about the context of the call to this action.
  */
 function comment_unpublish_by_keyword_action($comment, $context) {
   foreach ($context['keywords'] as $keyword) {
     if (strpos($comment->comment, $keyword) !== FALSE || strpos($comment->subject, $keyword) !== FALSE) {
-      db_update('comment')
-        ->fields(array('status' => COMMENT_NOT_PUBLISHED))
-        ->condition('cid', $comment->cid)
-        ->execute();
+      $comment->status = COMMENT_NOT_PUBLISHED;
       watchdog('action', 'Unpublished comment %subject.', array('%subject' => $comment->subject));
       break;
     }
@@ -2393,6 +2402,14 @@ function comment_unpublish_by_keyword_ac
 }
 
 /**
+ * Action to save a comment.
+ */
+function comment_save_action($comment) {
+  comment_save($comment);
+  watchdog('action', 'Saved comment %title', array('%title' => $comment->subject));
+}
+
+/**
  * Implement hook_ranking().
  */
 function comment_ranking() {
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1131
diff -u -p -r1.1131 node.module
--- modules/node/node.module	23 Sep 2009 10:41:55 -0000	1.1131
+++ modules/node/node.module	23 Sep 2009 15:43:58 -0000
@@ -2760,76 +2760,70 @@ function node_action_info() {
       'type' => 'node',
       'label' => t('Publish content'),
       'configurable' => FALSE,
-      'behavior' => array('changes_node_property'),
-      'triggers' => array('node_presave', 'comment_insert', 'comment_update'),
+      'behavior' => array(
+        'before' => 'node_save_action',
+      ),
+      'triggers' => array('node_presave', 'comment_insert', 'comment_update', 'comment_delete'),
     ),
     'node_unpublish_action' => array(
       'type' => 'node',
       'label' => t('Unpublish content'),
       'configurable' => FALSE,
-      'behavior' => array('changes_node_property'),
-      'triggers' => array(
-        'node_presave',
-        'comment_insert',
-        'comment_update',
-        'comment_delete'
+      'behavior' => array(
+        'before' => 'node_save_action',
       ),
+      'triggers' => array('node_presave', 'comment_insert', 'comment_update', 'comment_delete'),
     ),
     'node_make_sticky_action' => array(
       'type' => 'node',
       'label' => t('Make content sticky'),
       'configurable' => FALSE,
-      'behavior' => array('changes_node_property'),
-      'triggers' => array('node_presave', 'comment_insert', 'comment_update'),
+      'behavior' => array(
+        'before' => 'node_save_action',
+      ),
+      'triggers' => array('node_presave', 'comment_insert', 'comment_update', 'comment_delete'),
     ),
     'node_make_unsticky_action' => array(
       'type' => 'node',
       'label' => t('Make content unsticky'),
       'configurable' => FALSE,
-      'behavior' => array('changes_node_property'),
-      'triggers' => array(
-        'node_presave',
-        'comment_insert',
-        'comment_update',
-        'comment_delete'
+      'behavior' => array(
+        'before' => 'node_save_action',
       ),
+      'triggers' => array('node_presave', 'comment_insert', 'comment_update', 'comment_delete'),
     ),
     'node_promote_action' => array(
       'type' => 'node',
       'label' => t('Promote content to front page'),
       'configurable' => FALSE,
-      'behavior' => array('changes_node_property'),
-      'triggers' => array('node_presave', 'comment_insert', 'comment_update'),
+      'behavior' => array(
+        'before' => 'node_save_action',
+      ),
+      'triggers' => array('node_presave', 'comment_insert', 'comment_update', 'comment_delete'),
     ),
     'node_unpromote_action' => array(
       'type' => 'node',
       'label' => t('Remove content from front page'),
       'configurable' => FALSE,
-      'behavior' => array('changes_node_property'),
-      'triggers' => array(
-        'node_presave',
-        'comment_insert',
-        'comment_update',
-        'comment_delete'
+      'behavior' => array(
+        'before' => 'node_save_action',
       ),
+      'triggers' => array('node_presave', 'comment_insert', 'comment_update', 'comment_delete'),
     ),
     'node_assign_owner_action' => array(
       'type' => 'node',
       'label' => t('Change the author of content'),
       'configurable' => TRUE,
-      'behavior' => array('changes_node_property'),
-      'triggers' => array(
-        'node_presave',
-        'comment_insert',
-        'comment_update',
-        'comment_delete',
+      'behavior' => array(
+        'before' => 'node_save_action',
       ),
+      'triggers' => array('node_presave', 'comment_insert', 'comment_update', 'comment_delete'),
     ),
     'node_save_action' => array(
       'type' => 'node',
       'label' => t('Save content'),
       'configurable' => FALSE,
-      'triggers' => array('comment_delete', 'comment_insert', 'comment_update'),
+      'triggers' => array('comment_insert', 'comment_update', 'comment_delete'),
     ),
     'node_unpublish_by_keyword_action' => array(
       'type' => 'node',
Index: modules/system/system.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v
retrieving revision 1.76
diff -u -p -r1.76 system.api.php
--- modules/system/system.api.php	19 Sep 2009 11:07:36 -0000	1.76
+++ modules/system/system.api.php	23 Sep 2009 16:09:51 -0000
@@ -2245,13 +2245,14 @@ function hook_file_mimetype_mapping_alte
  *   - 'triggers': An array of the events (that is, hooks) that can trigger this
  *     action. For example: array('node_insert', 'user_update'). You can also
  *     declare support for any trigger by returning array('any') for this value.
- *   - 'behavior': (optional) machine-readable array of behaviors of this
- *     action, used to signal additional actions that may need to be triggered.
- *     Currently recognized behaviors by Trigger module:
- *     - 'changes_node_property': If an action with this behavior is assigned to
- *       a trigger other than 'node_presave', any node save actions also
- *       assigned to this trigger are moved later in the list. If a node save
- *       action is not present, one will be added.
+ *   - 'behavior': (optional) A machine-readable array of behaviors of this
+ *     action, used to signal additionally required actions that may need to be
+ *     triggered. Currently recognized behaviors by Trigger module:
+ *     - 'before': Specifies the internal name of an action that needs to be
+ *       invoked afterwards. For example, the 'node_publish' action is assigned
+ *       to a trigger other than 'node_presave', the 'node_save_action' has to
+ *       be invoked afterwards. If it already exists, it is moved later in the
+ *       list. Otherwise, it will be added.
  */
 function hook_action_info() {
   return array(
@@ -2259,12 +2260,21 @@ function hook_action_info() {
       'type' => 'comment',
       'label' => t('Unpublish comment'),
       'configurable' => FALSE,
-      'triggers' => array('comment_insert', 'comment_update'),
+      'behavior' => array(
+        'before' => 'comment_save_action',
+      ),
+      'triggers' => array('comment_presave', 'comment_insert', 'comment_update'),
     ),
     'comment_unpublish_by_keyword_action' => array(
       'type' => 'comment',
       'label' => t('Unpublish comment containing keyword(s)'),
       'configurable' => TRUE,
+      'triggers' => array('comment_presave', 'comment_insert', 'comment_update'),
+    ),
+    'comment_save_action' => array(
+      'type' => 'comment',
+      'label' => t('Save comment'),
+      'configurable' => FALSE,
       'triggers' => array('comment_insert', 'comment_update'),
     ),
   );
Index: modules/trigger/trigger.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/trigger/trigger.admin.inc,v
retrieving revision 1.18
diff -u -p -r1.18 trigger.admin.inc
--- modules/trigger/trigger.admin.inc	19 Sep 2009 11:07:36 -0000	1.18
+++ modules/trigger/trigger.admin.inc	23 Sep 2009 16:22:31 -0000
@@ -204,49 +204,51 @@ function trigger_assign_form_validate($f
 /**
  * Submit function for trigger_assign_form().
  */
-function trigger_assign_form_submit($form, $form_state) {
-  $form_values = $form_state['values'];
-
-  if (!empty($form_values['aid'])) {
-    $aid = actions_function_lookup($form_values['aid']);
+function trigger_assign_form_submit($form, &$form_state) {
+  if (!empty($form_state['values']['aid'])) {
+    $aid = actions_function_lookup($form_state['values']['aid']);
     $weight = db_query("SELECT MAX(weight) FROM {trigger_assignments} WHERE hook = :hook", array(
-      ':hook' => $form_values['hook'],
+      ':hook' => $form_state['values']['hook'],
     ))->fetchField();
 
     db_insert('trigger_assignments')
       ->fields(array(
-        'hook' => $form_values['hook'],
+        'hook' => $form_state['values']['hook'],
         'aid' => $aid,
         'weight' => $weight + 1,
       ))
       ->execute();
-    // If this action changes a node property, we need to save the node
+    // If this action changes an object property, we need to save the object,
     // so the change will persist.
-
     $actions = actions_list();
-    if (isset($actions[$aid]['behavior']) && in_array('changes_node_property', $actions[$aid]['behavior']) && ($form_values['hook'] != 'node_presave') && ($form_values['hook'] != 'comment_presave')) {
-      // Delete previous node_save_action if it exists, and re-add a new one at
+    if (isset($actions[$aid]['behavior']['before']) && strpos($form_state['values']['hook'], 'presave') === FALSE) {
+      // Delete the action that must run after if it exists, and re-add it with
       // a higher weight.
       $save_post_action_assigned = db_query("SELECT aid FROM {trigger_assignments} WHERE hook = :hook AND aid = :aid", array(
-        ':hook' => $form_values['hook'],
-        ':aid' => 'node_save_action',
+        ':hook' => $form_state['values']['hook'],
+        ':aid' => $actions[$aid]['behavior']['before'],
       ))->fetchField();
 
       if ($save_post_action_assigned) {
         db_delete('trigger_assignments')
-          ->condition('hook', $form_values['hook'])
-          ->condition('aid', 'node_save_action')
+          ->condition('hook', $form_state['values']['hook'])
+          ->condition('aid', $actions[$aid]['behavior']['before'])
           ->execute();
       }
       db_insert('trigger_assignments')
         ->fields(array(
-          'hook' => $form_values['hook'],
-          'aid' => 'node_save_action',
+          'hook' => $form_state['values']['hook'],
+          'aid' => $actions[$aid]['behavior']['before'],
           'weight' => $weight + 2,
         ))
         ->execute();
-      if (!$save_post_action_assigned) {
-        drupal_set_message(t("You have added an action that changes a the property of some content. Your 'Save content' action has been moved later in the list so that the property change will be saved."));
+      // If an existing action was moved, inform the user.
+      if ($save_post_action_assigned) {
+        drupal_set_message(t("The added action changes a property of the content. The %label action has been moved later in the list so that the property change will be saved.", array('%label' => $actions[$actions[$aid]['behavior']['before']]['label'])));
+      }
+      // Otherwise, inform the user about the added, required action.
+      else {
+        drupal_set_message(t("The %label action has been appended after the added action in the list so that the property change will be saved.", array('%label' => $actions[$actions[$aid]['behavior']['before']]['label'])));
       }
     }
   }
Index: modules/trigger/trigger.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/trigger/trigger.module,v
retrieving revision 1.48
diff -u -p -r1.48 trigger.module
--- modules/trigger/trigger.module	19 Sep 2009 11:07:36 -0000	1.48
+++ modules/trigger/trigger.module	23 Sep 2009 16:15:18 -0000
@@ -106,7 +106,10 @@ function trigger_trigger_info() {
        ),
      ),
      'comment' => array(
-         'comment_insert' => array(
+       'comment_presave' => array(
+         'label' => t('When either saving a new comment or updating an existing comment'),
+       ),
+       'comment_insert' => array(
          'label' => t('After saving a new comment'),
        ),
        'comment_update' => array(
@@ -346,6 +349,13 @@ function _trigger_normalize_comment_cont
 }
 
 /**
+ * Implement hook_comment_presave().
+ */
+function trigger_comment_presave($comment) {
+  _trigger_comment($comment, 'comment_presave');
+}
+
+/**
  * Implement hook_comment_insert().
  */
 function trigger_comment_insert($comment) {
@@ -404,7 +414,6 @@ function _trigger_comment($a1, $hook) {
       actions_do($aid, $objects[$type], $context);
     }
     else {
-      $a1 = (object) $a1;
       actions_do($aid, $a1, $context);
     }
   }
