Index: activity.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/activity/Attic/activity.admin.inc,v
retrieving revision 1.1.2.40
diff -u -p -r1.1.2.40 activity.admin.inc
--- activity.admin.inc	12 Apr 2010 16:36:56 -0000	1.1.2.40
+++ activity.admin.inc	16 May 2010 23:27:48 -0000
@@ -132,8 +132,10 @@ function activity_form_submit($form, &$f
       $params['everyone-pattern-' . $id] = $values['messages']['everyone-pattern-' . $id];
     }
     $desc = $values['messages']['description'];
+    $update = TRUE;
     if (!$aid = $values['messages']['aid']) {
       $aid = NULL;
+      $update = FALSE;
     }
     
     // handle the types, thanks Checkboxes :-D
@@ -146,6 +148,13 @@ function activity_form_submit($form, &$f
     
     // Save the action
     include_once('includes/actions.inc');
+    // In order to save the aid into the actions.parameters column, when a new
+    // template is created, the aid must be generated. Can look into using
+    // {actions_aid} table for this as well. SELECT aid + 1 ORDER BY aid DESC ?
+    if (!$update) {
+      $aid = actions_save('activity_record', 'activity', $params, $desc);
+    }
+    $params['aid'] = $aid;
     $aid = actions_save('activity_record', 'activity', $params, $desc, $aid);
 
     // Save the trigger assignment
@@ -447,6 +456,12 @@ function activity_actions_delete_form(&$
     '#type' => 'hidden',
     '#value' => $action->aid,
   );
+  $form['delete_existing'] = array(
+    '#type' => 'checkbox',
+    '#default_value' => 0,
+    '#title' => t('Delete Existing Activities for this template'),
+    '#weight' => 1,
+  );
   return confirm_form($form,
     t('Are you sure you want to delete the action %action?', array('%action' => $action->description)),
     'admin/settings/actions/manage',
@@ -467,6 +482,18 @@ function activity_actions_delete_form_su
   watchdog('user', 'Deleted action %aid (%action)', array('%aid' => $aid, '%action' => $action->description));
   drupal_set_message(t('Action %action was deleted', array('%action' => $description)));
   $form_state['redirect'] = 'admin/build/activity';
+
+  if (!empty($form_state['values']['delete_existing'])) {
+    $batch = array(
+      'title' => t('Deleting Existing @title', array('@title' => $action->description)),
+      'operations' => array(
+        array('activity_batch_delete', array($aid)),
+      ),
+      'file' => drupal_get_path('module', 'activity') . '/activity.admin.inc',
+    );
+
+    batch_set($batch);
+  }
 }
 
 /**
@@ -649,4 +676,131 @@ function activity_access_rebuild_process
     // If finished, delete the sandbox.
     unset($context['sandbox']);
   } 
+}
+
+/**
+ * Set a batch process to regenerate activity for a specific hook and op pair.
+ *
+ * @param $aid
+ *  The actions.aid for this template.
+ *
+ * @return none
+ */
+function activity_batch_regenerate($batches) {
+  $batch_set = FALSE;
+  foreach ($batches as $aid => $batch) {
+    $trigger_assignment = db_fetch_object(db_query("SELECT hook, op FROM {trigger_assignments} WHERE aid = '%s'", $aid));
+    if (!empty($trigger_assignment)) {
+      $batch_set = TRUE;
+      $batch = array(
+        'title' => t('Regenerating @description Activity', array('@description' => db_result(db_query("SELECT description from {actions} WHERE aid = '%s'", $aid)))),
+        'operations' => array(
+          array('activity_batch_delete', array($aid)),
+          array('activity_batch_regenerate_step', array($aid, $batch, $trigger_assignment->hook, $trigger_assignment->op)),
+        ),
+        'file' => drupal_get_path('module', 'activity') . '/activity.admin.inc',
+      );
+
+      batch_set($batch);
+    }
+  }
+
+  if ($batch_set) {
+    batch_process('admin/build/activity');
+  }
+  else {
+    return '';
+  }
+}
+
+/**
+ * Batch deletion step.
+ *
+ * @param $aid
+ *  The actions.aid for this template.
+ * @param $batch_context
+ *  The context array for this batch operation.
+ */
+function activity_batch_delete($aid, &$batch_context) {
+  if (!isset($batch_context['sandbox']['last_activity_id'])) {
+    $batch_context['sandbox']['last_activity_id'] = 0;
+    $batch_context['sandbox']['progress'] = 0;
+    $batch_context['sandbox']['max'] = db_result(db_query("SELECT COUNT(aid) FROM {activity} WHERE actions_id = '%s'", $aid));
+  }
+  $limit = 200;
+  $activity_to_be_deleted = db_query_range("SELECT aid FROM {activity} WHERE aid > %d AND actions_id = '%s' ORDER BY aid ASC", $batch_context['sandbox']['last_activity_id'], $aid, 0, $limit);
+  $activity_ids = array();
+  while ($row = db_fetch_object($activity_to_be_deleted)) {
+    $activity_ids[] = $row->aid;
+    $batch_context['sandbox']['last_activity_id'] = $row->aid;
+    $batch_context['sandbox']['progress']++;
+  }
+
+  activity_delete($activity_ids);
+  // Check if not finished.
+  if ($batch_context['sandbox']['progress'] < $batch_context['sandbox']['max']) {
+    $batch_context['finished'] = $batch_context['sandbox']['progress'] / $batch_context['sandbox']['max'];
+  }
+  else {
+    // If finished, delete the sandbox.
+    unset($batch_context['sandbox']);
+  }
+  
+}
+
+/**
+ * Batch regeneration step.
+ *
+ * @param $aid
+ *  The actions.aid for this template.
+ * @param $hook
+ *  The name of the hook being recorded.
+ * @param $op
+ *  The op for the hook being recorded.
+ * @param $batch_context
+ *  An array representing the context for the batch operation.
+ */
+function activity_batch_regenerate_step($aid, $batch, $hook, $op, &$batch_context) {
+  $module = activity_module_name($hook);
+  $info  = activity_get_module_info($module);
+  $load_callback = $info->context_load_callback;
+  $limit = 50;
+
+  // Set up the sandbox for the regeneration.
+  if (!isset($batch_context['sandbox']['list'])) {
+    $batch_context['sandbox']['list'] = $batch;
+    $batch_context['sandbox']['max'] = count($batch_context['sandbox']['list']);
+    $batch_context['sandbox']['progress'] = 0;
+
+    $parameters = db_result(db_query("SELECT a.parameters FROM {actions} a WHERE aid = '%s'", $aid));
+    $batch_context['sandbox']['parameters'] = unserialize($parameters);
+  }
+
+  $count = 0;
+  foreach ($batch_context['sandbox']['list'] as $key => $event) {
+    $context = array();
+    if (++$count > $limit) {
+      break;
+    }
+    else {
+      $context = $load_callback($hook, $op, $event['id']);
+      if (!empty($context)) {
+        $context += array(
+          'created' => $event['created'],
+          'actor' => $event['actor'],
+        );
+        activity_record(NULL, $context + $batch_context['sandbox']['parameters']);
+      }
+      $batch_context['sandbox']['progress']++;
+    }
+    unset($batch_context['sandbox']['list'][$key]);
+  }
+  // Check if not finished.
+  if ($batch_context['sandbox']['progress'] < $batch_context['sandbox']['max']) {
+    $batch_context['finished'] = $batch_context['sandbox']['progress'] / $batch_context['sandbox']['max'];
+  }
+  else {
+    // If finished, delete the sandbox.
+    unset($batch_context['sandbox']);
+  }
 }
\ No newline at end of file
Index: activity.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/activity/activity.install,v
retrieving revision 1.1.2.1.2.6.2.4.2.15
diff -u -p -r1.1.2.1.2.6.2.4.2.15 activity.install
--- activity.install	16 May 2010 04:03:23 -0000	1.1.2.1.2.6.2.4.2.15
+++ activity.install	16 May 2010 23:27:48 -0000
@@ -1,5 +1,5 @@
 <?php
-// $Id: activity.install,v 1.1.2.1.2.6.2.4.2.15 2010/05/16 04:03:23 scottreynolds Exp $
+// $Id: activity.install,v 1.1.2.1.2.6.2.4.2.14 2010/04/26 16:31:52 scottreynolds Exp $
 
 function activity_install() {
   drupal_install_schema('activity');
@@ -55,12 +55,20 @@ function activity_schema() {
         'not null' => TRUE,
         'unsigned' => TRUE,
       ),
+      'actions_id' => array(
+        'description' => 'Foreign key to the actions table.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '0',
+      ),
     ),
     'primary key' => array('aid'),
     'indexes' => array(
       'nid' => array('nid'),
       'eid' => array('eid'),
-      'created' => array('created'),
+      'created' => array('created'), // Probably not at all useful.
+      'actions_id' => array('actions_id'),
     ),
   );
   
@@ -212,4 +220,23 @@ function activity_update_6201() {
   $ret = array();
   db_change_field($ret, 'activity_messages', 'amid', 'amid', array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE));
   return $ret;
+}
+
+/**
+ * Update {activity} table to have the actions_id field.
+ * @see: http://drupal.org/node/463854
+ */
+function activity_update_6202() {
+  $ret = array();
+
+  db_add_field($ret, 'activity', 'actions_id', array(
+        'description' => 'Foreign key to the actions table.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '0',
+      ),
+    array('indexes' => array('actions_id' => array('actions_id'))));
+
+  return $ret;
 }
\ No newline at end of file
Index: activity.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/activity/activity.module,v
retrieving revision 1.1.2.2.2.30.2.31.2.90
diff -u -p -r1.1.2.2.2.30.2.31.2.90 activity.module
--- activity.module	15 May 2010 23:59:20 -0000	1.1.2.2.2.30.2.31.2.90
+++ activity.module	16 May 2010 23:27:49 -0000
@@ -89,6 +89,9 @@ function comment_activity_info() {
   foreach (node_get_types() as $type) {
     $info->type_options[$type->type] = t($type->name);
   }
+
+  $info->list_callback = 'comment_list_activity_actions';
+  $info->context_load_callback = 'comment_load_activity_context';
   return $info;
 }
 
@@ -102,6 +105,9 @@ function node_activity_info() {
   foreach (node_get_types() as $type) {
     $info->type_options[$type->type] = t($type->name);
   }
+
+  $info->list_callback = 'node_list_activity_actions';
+  $info->context_load_callback = 'node_load_activity_context';
   return $info;
 }
 
@@ -112,6 +118,9 @@ function user_activity_info() {
   $info->objects = array('account' => 'account'); // array key is the label
   $info->hooks = array('user' => array('insert', 'update', 'login', 'logout', 'view'));
   $info->type_options = user_roles();
+
+  $info->list_callback = 'user_list_activity_actions';
+  $info->context_load_callback = 'user_load_activity_context';
   return $info;
 }
 
@@ -224,10 +233,59 @@ function activity_menu() {
     'file' => 'activity.admin.inc',
     'type' => MENU_CALLBACK,
   );
+  $items['admin/build/activity/batch/%activity_batch/%'] = array(
+    'title' => 'Batch Update',
+    'page callback' => 'activity_batch_regenerate',
+    'page arguments' => array(4),
+    'access callback' => 'activity_batch_access',
+    'access arguments' => array(4, 5),
+    'file' => 'activity.admin.inc',
+    'type' => MENU_CALLBACK,
+  );
   return $items;
 }
 
 /**
+ * Menu loader function to load batch-able action_id.
+ *
+ * @param $aid
+ *  The action id for the template.
+ *
+ * @return array / FALSE
+ *  An array of events to batch if the action is batch-able or FALSE
+ */
+function activity_batch_load($aid) {
+  $trigger_assignment = db_fetch_object(db_query("SELECT hook, op FROM {trigger_assignments} WHERE aid = '%s'", $aid));
+  if (!empty($trigger_assignment)) {
+    $module = activity_module_name($trigger_assignment->hook);
+    $info = activity_get_module_info($module);
+    if (!empty($info->list_callback) && !empty($info->context_load_callback)) {
+      $callback = $info->list_callback;
+      $listing = $callback($trigger_assignment->hook, $trigger_assignment->op);
+      if (!empty($listing)) {
+        return array($aid => $listing);
+      }
+    }
+  }
+  return FALSE;
+}
+
+/**
+ * Menu Access callback to start a batch regeneration.
+ *
+ * @param array $batch
+ *  The single batch operation.
+ * @param string $token
+ *  The token generated for this action.aid.
+ *
+ * @return TRUE/FALSE
+ */
+function activity_batch_access($batch, $token) {
+  return user_access('administer activity') && drupal_valid_token($token, key($batch));
+}
+
+
+/**
  * Menu Access callback for delete Activity.
  *
  * @param int $aid
@@ -398,11 +456,11 @@ function activity_token_values($type, $o
  * activity_get_module_info()
  */
 function activity_record_check($object, $context, $token_objects, $activity_object) {
-  global $user;
+  $account = user_load($context['actor']);
 
   // First check to see if the user opts out.
   $aid = db_result(db_query("SELECT aid FROM {trigger_assignments} WHERE hook = '%s' AND op = '%s'", $context['hook'], $context['op']));
-  if (isset($user->activity_ignore[$aid]) && $user->activity_ignore[$aid] == 0) {
+  if (isset($account->activity_ignore[$aid]) && $account->activity_ignore[$aid] == 0) {
     // user has opted out of this particular action
     return FALSE;
   }
@@ -429,7 +487,10 @@ function activity_record_check($object, 
  *  holds the messages
  */
 function activity_record($object, $context) {
-  global $user;
+  $context += array(
+    'actor' => $GLOBALS['user']->uid,
+    'created' => time(),
+  );
   // find what the type is so we can do the tokenizing
   $activity_object = FALSE;
   foreach (activity_get_module_info() as $module => $info) {
@@ -463,9 +524,8 @@ function activity_record($object, $conte
     $objects[$type] = drupal_clone($context[$type]);
   }
 
-  // @TODO: when doing a bulk update this will break.
-  if (!empty($user->uid) && $user->uid != $objects[$type]->uid) {
-    $objects[$type]->uid = $user->uid;
+  if (!empty($context['actor']) && $context['actor'] != $objects[$type]->uid) {
+    $objects[$type]->uid = $context['actor'];
   }
   
   drupal_alter('activity_objects', $objects, $type);
@@ -520,11 +580,12 @@ function activity_record($object, $conte
   }
 
   $record = new stdClass();
-  $record->uid = (!empty($objects[$type]->uid)) ? $objects[$type]->uid : $user->uid;
+  $record->uid = $context['actor'];
   $record->op = $context['op'];
   $record->type = $activity_object->name;
   $record->nid = $nid;
-  $record->created = time(); // for PHP4 compat. for D7 use REQUEST_TIME
+  $record->created = $context['created'];
+  $record->actions_id = $context['aid'];
   
   // handle the entity id
   if (!empty($info->eid_field) && isset($context[$type]->{$info->eid_field})) {
@@ -790,11 +851,17 @@ function activity_theme($existing, $type
 function theme_activity_settings_actions_list($results) {
   $header = array(t('Module'), t('Trigger'), t('Operations'));
   foreach ($results as $result) {
+    $links = array(
+      l('configure', 'admin/build/activity/configure/'. $result['aid']),
+      l('delete', 'admin/build/activity/delete/'. $result['aid'])
+    );
+    if (activity_batch_load($result['aid'])) {
+      $links[] = l('regenerate', 'admin/build/activity/batch/' . $result['aid'] . '/' . drupal_get_token($result['aid']));
+    }
     $rows[] = array(
       drupal_ucfirst(str_replace('_', ' ', $result['hook'])),
       $result['description'],
-      l('configure', 'admin/build/activity/configure/'. $result['aid']) .' | '.
-      l('delete', 'admin/build/activity/delete/'. $result['aid']),
+      implode(' | ', $links),
     );
   }
   $output = theme('table', $header, $rows);
Index: modules/comment.activity.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/activity/modules/Attic/comment.activity.inc,v
retrieving revision 1.1.2.21
diff -u -p -r1.1.2.21 comment.activity.inc
--- modules/comment.activity.inc	15 May 2010 22:29:17 -0000	1.1.2.21
+++ modules/comment.activity.inc	16 May 2010 23:27:49 -0000
@@ -86,4 +86,59 @@ function comment_activity_objects_alter(
       $token_objects['node_comment_author'] = $token_objects['comment'];
     }
   }
+}
+
+/**
+ * List all the Activity Actions that match the hook and op.
+ *
+ * @param string $hook
+ *  The hook that is to be fired.
+ * @param string $op
+ *  The op to be used in the hook.
+ *
+ * @return array
+ *  An array of arrays with 'id', 'created' and 'actor' keys.
+ */
+function comment_list_activity_actions($hook, $op) {
+  $actions = array();
+  if ($op == 'insert') {
+    $sql = 'SELECT cid as id, timestamp as created, uid as actor FROM {comments}';
+  }
+
+  if (isset($sql)) {
+    $result = db_query($sql);
+    while ($row = db_fetch_array($result)) {
+      $actions[] = $row;
+    }
+  }
+
+  return $actions;
+}
+
+/**
+ * Load up the context array to pass to activity_record.
+ *
+ * @param string $hook
+ *  The hook that is being fired.
+ * @param string $op
+ *  The op for that hook.
+ * @param string $id
+ *  The id for the action.
+ *
+ * @return array
+ *   The context array for activity_record.
+ * @see trigger_comment
+ */
+function comment_load_activity_context($hook, $op, $id) {
+  $comment = _comment_load($id);
+  $context = array();
+  if (!empty($comment)) {
+    $context = array(
+      'hook' => $hook,
+      'op' => $op,
+      'comment' => $comment,
+    );
+  }
+
+  return $context;
 }
\ No newline at end of file
Index: modules/node.activity.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/activity/modules/Attic/node.activity.inc,v
retrieving revision 1.1.2.20
diff -u -p -r1.1.2.20 node.activity.inc
--- modules/node.activity.inc	15 May 2010 22:29:17 -0000	1.1.2.20
+++ modules/node.activity.inc	16 May 2010 23:27:49 -0000
@@ -79,3 +79,61 @@ function node_activity_objects_alter(&$t
     $token_objects['user'] = $GLOBALS['user'];
   }
 }
+
+/**
+ * List all the Activity Actions that match the hook and op.
+ *
+ * @param string $hook
+ *  The hook that is to be fired.
+ * @param string $op
+ *  The op to be used in the hook.
+ *
+ * @return array
+ *  An array of arrays with 'id', 'created' and 'actor' keys.
+ */
+function node_list_activity_actions($hook, $op) {
+  $actions = array();
+  if ($op == 'insert' ) {
+    $sql = "SELECT nid as id, created as created, uid as actor FROM {node}";
+  }
+  elseif ($op == 'view') {
+    $sql = "SELECT nid as id, timestamp as created, uid as actor FROM {history}";
+  }
+
+  if (isset($sql)) {
+    $result = db_query($sql);
+    while ($row = db_fetch_array($result)) {
+      $actions[] = $row;
+    }
+  }
+
+  return $actions;
+}
+
+/**
+ * Load up the context array to pass to activity_record.
+ *
+ * @param string $hook
+ *  The hook that is being fired.
+ * @param string $op
+ *  The op for that hook.
+ * @param string $id
+ *  The id for the action.
+ *
+ * @return array
+ *   The context array for activity_record.
+ * @see trigger_nodeapi
+ */
+function node_load_activity_context($hook, $op, $id) {
+  $node = node_load($id);
+  $context = array();
+  if (!empty($node)) {
+    $context = array(
+      'hook' => $hook,
+      'op' => $op,
+      'node' => $node,
+    );
+  }
+
+  return $context;
+}
\ No newline at end of file
Index: modules/user.activity.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/activity/modules/Attic/user.activity.inc,v
retrieving revision 1.1.2.17
diff -u -p -r1.1.2.17 user.activity.inc
--- modules/user.activity.inc	15 May 2010 22:29:17 -0000	1.1.2.17
+++ modules/user.activity.inc	16 May 2010 23:27:49 -0000
@@ -41,4 +41,60 @@ function user_activity_token_values($typ
     );
   }
   return array();
+}
+
+/**
+ * List all the Activity Actions that match the hook and op.
+ *
+ * @param string $hook
+ *  The hook that is to be fired.
+ * @param string $op
+ *  The op to be used in the hook.
+ *
+ * @return array
+ *  An array of arrays with 'id', 'created' and 'actor' keys.
+ */
+function user_list_activity_actions($hook, $op) {
+  $actions = array();
+  if ($op == 'insert') {
+    $sql = "SELECT uid as id, created as created, uid as actor FROM {users} WHERE uid <> 0";
+  }
+
+  if (isset($sql)) {
+    $result = db_query($sql);
+    while ($row = db_fetch_array($result)) {
+      $actions[] = $row;
+    }
+  }
+
+  return $actions;
+}
+
+/**
+ * Load up the context array to pass to activity_record.
+ *
+ * @param string $hook
+ *  The hook that is being fired.
+ * @param string $op
+ *  The op for that hook.
+ * @param string $id
+ *  The id for the action.
+ *
+ * @return array
+ *   The context array for activity_record.
+ * @see trigger_user
+ */
+function user_load_activity_context($hook, $op, $id) {
+  $account = user_load($id);
+  $context = array();
+  if (!empty($account)) {
+    $context = array(
+      'hook' => $hook,
+      'op' => $op,
+      'form_values' => array(),
+      'account' => $account,
+    );
+  }
+
+  return $context;
 }
\ No newline at end of file
