? rules-455560.patch
Index: rules_scheduler/rules_scheduler.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/rules/rules_scheduler/Attic/rules_scheduler.install,v
retrieving revision 1.1.2.5
diff -u -p -r1.1.2.5 rules_scheduler.install
--- rules_scheduler/rules_scheduler.install	19 Apr 2009 18:19:07 -0000	1.1.2.5
+++ rules_scheduler/rules_scheduler.install	3 Jul 2009 16:26:30 -0000
@@ -52,6 +52,13 @@ function rules_scheduler_schema() {
         'serialize' => TRUE,
         'description' => t('The whole, serialized item configuration.'),
       ),
+      'identifier' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'default' => '',
+        'not null' => FALSE,
+        'description' => t('The user defined string identifying this task.'),
+      ),
     ),
     'primary key' => array('tid'),
     'indexes' => array('date' => array('date')),
@@ -59,3 +66,19 @@ function rules_scheduler_schema() {
   return $schema;
 }
 
+/**
+ * Implementation of hook_update_N().
+ */
+function rules_scheduler_update_6100() {
+  $spec = array(
+    'type' => 'varchar',
+    'length' => '255',
+    'default' => '',
+    'not null' => FALSE,
+    'description' => t('The user defined string identifying this task.'),
+  );
+  $ret = array();
+  db_add_field($ret, 'rules_scheduler', 'identifier', $spec);
+  return $ret;
+}
+
Index: rules_scheduler/rules_scheduler.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/rules/rules_scheduler/Attic/rules_scheduler.module,v
retrieving revision 1.1.2.4
diff -u -p -r1.1.2.4 rules_scheduler.module
--- rules_scheduler/rules_scheduler.module	19 Apr 2009 15:03:43 -0000	1.1.2.4
+++ rules_scheduler/rules_scheduler.module	3 Jul 2009 16:26:31 -0000
@@ -6,6 +6,9 @@
  * @file Rules scheduler module
  */
 
+// Path definition for scheduling page
+define('RULES_SCHEDULER_PATH', RULES_ADMIN_SET_PATH .'/scheduling');
+
 /**
  * Implementation of hook_cron().
  */
@@ -28,3 +31,256 @@ function rules_scheduler_cron() {
   }
 }
 
+/**
+ * Implementation of hook_menu().
+ */
+function rules_scheduler_menu() {
+  $items = array();
+  $items[RULES_SCHEDULER_PATH] = array(
+    'title' => 'Scheduling',
+    'type' => MENU_LOCAL_TASK,
+    'page callback' => 'rules_scheduler_scheduling',
+    'access arguments' => array('administer rules'),
+  );
+  $items[RULES_SCHEDULER_PATH .'/%rules_scheduler_tid/delete'] = array(
+    'title' => 'Delete a scheduled task',
+    'type' => MENU_CALLBACK,
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_scheduler_delete_task', 4),
+    'access arguments' => array('administer rules'),
+    'load arguments' => array(4),
+  );
+  return $items;
+}
+
+function rules_scheduler_scheduling() {
+  return drupal_get_form('rules_scheduler_form');
+}
+
+function rules_scheduler_form($form_state) {
+  $form = array();
+  // Display view for all scheduled tasks
+  if (module_exists('views')) {
+    $task_list = views_embed_view('rules_scheduler');
+  }
+  else {
+    $task_list = t('To display scheduled tasks you have to install the <a href="http://drupal.org/project/views">Views</a> module.');
+  }
+  $form['task_view'] = array(
+    '#type' => 'markup',
+    '#value' => $task_list,
+  );
+  
+  // form fieldset for manual scheduling
+  $form['manual_scheduling'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Manual scheduling of rule sets without arguments'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+  $rulesets = rules_scheduler_rulesets_without_arguments();
+  if (empty($rulesets)) {
+    $form['manual_scheduling']['#description'] = t('There are currently no rule sets without arguments available.');
+  } else {
+     $form['manual_scheduling']['ruleset_manual'] = array(
+      '#title' => t('Rule set name'),
+      '#type' => 'select',
+      '#options' => $rulesets,
+      '#multiple' => FALSE,
+    );
+    $form['manual_scheduling']['task_identifier'] = array(
+      '#title' => t('Identifier'),
+      '#type' => 'textfield',
+      '#description' => t('User provided string to identify the task.'),
+    );
+    $rules_date = new rules_data_type_date();
+    $form['manual_scheduling']['date'] = $rules_date->get_default_input_form(array('label' => 'Execution date'), NULL);
+    $form['manual_scheduling']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Schedule'),
+      '#submit' => array('rules_scheduler_manual_submit'),
+    );
+  }
+  
+  // form fieldset for deleting by rule set name
+  $result = db_query("SELECT DISTINCT set_name FROM {rules_scheduler}");
+  $ruleset_names = array();
+  while ($name = db_fetch_array($result)) {
+    $ruleset_names[$name['set_name']] = $name['set_name'];
+  }
+  
+  $form['delete_by_ruleset_name'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Delete tasks by rule set name'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+  if (empty($ruleset_names)) {
+    $form['delete_by_ruleset_name']['#description'] = t('There are currently no scheduled tasks available to delete.');
+  } else {
+    $form['delete_by_ruleset_name']['ruleset_delete'] = array(
+      '#title' => t('Rule set name'),
+      '#type' => 'select',
+      '#options' => $ruleset_names,
+      '#multiple' => FALSE,
+    );
+    $form['delete_by_ruleset_name']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Delete'),
+      '#submit' => array('rules_scheduler_delete_submit'),
+    );
+  }
+  
+  return $form;
+}
+
+function rules_scheduler_rulesets_without_arguments() {
+  $rule_sets = array();
+  foreach (rules_get_configured_items('rule_sets') as $name => $set_info) {
+    if (empty($set_info['arguments'])) {
+      $rule_sets[$name] = $set_info['label'] .' ('. $name .')';
+    }
+  }
+  return $rule_sets;
+}
+
+function rules_scheduler_manual_submit($form, &$form_state) {
+  $pack = rules_pack_variables(array(), NULL);
+  if ($pack === FALSE) {
+    rules_log(t('Packing arguments for scheduling the rule set %set failed.', array('%set' => $element['#info']['set'])), TRUE);
+  }
+  else {
+    $rules_date = new rules_data_type_date();
+    $date = $rules_date->check_value(array('label' => 'execution date'), $form_state['values']['date']);
+    drupal_write_record('rules_scheduler', $task = array(
+        'date' => $date,
+        'set_name' => $form_state['values']['ruleset_manual'],
+        'arguments' => $pack,
+        'identifier' => $form_state['values']['task_identifier'],
+      ));
+  }
+  drupal_set_message(t('The rule set %name has been scheduled on %date.', array('%name' => $form_state['values']['ruleset_manual'], '%date' => $date)));
+}
+
+function rules_scheduler_delete_submit($form, &$form_state) {
+  require_once('rules_scheduler.rules.inc');
+  rules_scheduler_action_delete(NULL, $form_state['values']['ruleset_delete']);
+  drupal_set_message(t('All tasks associated with %ruleset have been deleted.', array('%ruleset' => $form_state['values']['ruleset_delete'])));
+}
+
+function rules_scheduler_tid_load($tid) {
+  $result = db_query("SELECT * FROM {rules_scheduler} WHERE tid = %d", $tid);
+  $task = db_fetch_array($result);
+  return $task;  
+}
+
+function rules_scheduler_delete_task(&$form_state, $task) {
+  $form = array();
+  $form_state['task'] = $task;
+
+  $path = array();
+  $path['path'] = isset($_GET['destination']) ? $_GET['destination'] : RULES_SCHEDULER_PATH;
+  
+  $title = t('Are you sure you want to delete task %tid?', array('%tid' => $task['tid']));
+  if (!empty($task['identifier'])) {
+    $msg = t('This task refers to the custom identifier %id and rule set %ruleset, it will be executed on %date. The delete action cannot be undone.', array(
+      '%ruleset' => $task['set_name'],
+      '%id' => $task['identifier'],
+      '%date' => $task['date'],
+    ));
+  } else {
+    $msg = t('This task refers to the rule set %ruleset and will be executed on %date. The delete action cannot be undone.', array(
+      '%ruleset' => $task['set_name'],
+      '%id' => $task['identifier'],
+      '%date' => $task['date'],
+    ));
+  }
+  return confirm_form($form, $title, $path, $msg, t('Delete'), t('Cancel'));
+}
+
+function rules_scheduler_delete_task_submit($form, &$form_state) {
+  db_query("DELETE FROM {rules_scheduler} WHERE tid = %d", $form_state['task']['tid']);
+  drupal_set_message(t("Task %label has been deleted.", array('%label' => $form_state['task']['tid'])));
+  $form_state['redirect'] = RULES_SCHEDULER_PATH;
+}
+
+
+/**
+ * Implementation of hook_views_data().
+ */
+function rules_scheduler_views_data() {
+  $table = array(
+    'rules_scheduler' => array(
+      'table' => array(
+        'group' => 'Rules scheduler',
+        'base' => array(
+          'field' => 'tid',
+          'title' => t('Scheduled rule sets'),
+          'help' => t("Scheduled rules that are executed based on time and cron"),
+          'weight' => -10,
+        ),
+      ),
+      'tid' => array(
+        'title' => t('Tid'),
+        'help' => t('The internal ID of the scheduled rule set'),
+        'field' => array(
+          'click sortable' => TRUE,
+        ),
+        'filter' => array(
+          'handler' => 'views_handler_filter_numeric',
+        ),
+        'sort' => array(
+          'handler' => 'views_handler_sort',
+        ),
+      ),
+      'set_name' => array(
+        'title' => t('Rule set name'),
+        'help' => t('The name of the rule set'),
+        'field' => array(
+          'click sortable' => TRUE,
+        ),
+        'filter' => array(
+          'handler' => 'views_handler_filter',
+        ),
+        'sort' => array(
+          'handler' => 'views_handler_sort',
+        ),
+      ),
+      'date' => array(
+        'title' => t('Scheduled date'),
+        'help' => t('Scheduled date and time stamp'),
+        'field' => array(
+          'handler' => 'rules_scheduler_datetime',
+          'click sortable' => TRUE,
+        ),
+        'filter' => array(
+          'handler' => 'views_handler_filter',
+        ),
+        'sort' => array(
+          'handler' => 'views_handler_sort',
+        ),
+      ),
+      'identifier' => array(
+        'title' => t('User provided identifier'),
+        'help' => t('ID to recognize this specific scheduled task'),
+        'field' => array(
+          'click sortable' => TRUE,
+        ),
+        'filter' => array(
+          'handler' => 'views_handler_filter',
+        ),
+        'sort' => array(
+          'handler' => 'views_handler_sort',
+        ),
+      ),
+    ),
+  );
+  return $table;
+}
+
+/**
+ * Implementation of hook_views_api().
+ */
+function rules_scheduler_views_api() {
+  return array('api' => 2.0);
+}
\ No newline at end of file
Index: rules_scheduler/rules_scheduler.rules.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/rules/rules_scheduler/Attic/rules_scheduler.rules.inc,v
retrieving revision 1.1.2.4
diff -u -p -r1.1.2.4 rules_scheduler.rules.inc
--- rules_scheduler/rules_scheduler.rules.inc	19 Apr 2009 15:03:43 -0000	1.1.2.4
+++ rules_scheduler/rules_scheduler.rules.inc	3 Jul 2009 16:26:31 -0000
@@ -26,7 +26,30 @@ function rules_scheduler_rules_action_in
         'label' => t('Scheduled evaluation date'),
       ));
     $item['arguments'] = array_merge($date_arg, $item['arguments']);
+    $identifier_arg = array('task_identifier' => array(
+        'type' => 'string',
+        'label' => t('Identifier'),
+        'description' => t('User provided string to identify the task.'),
+      ));
+    $item['arguments'] = array_merge($identifier_arg, $item['arguments']);
   }
+  // Add action to delete scheduled rule sets
+  $items['rules_action_delete_scheduled_set'] = array(
+    'label' => t('Delete scheduled rule sets'),
+    'module' => 'Rule Scheduler',
+    'base' => 'rules_scheduler_action_delete',
+    'arguments' => array(
+      'task_identifier' => array(
+        'type' => 'string',
+        'label' => t('Identifier'),
+        'description' => t('User provided string to identify the task.'),
+      ),
+      'ruleset' => array(
+        'type' => 'string',
+        'label' => t('Rule set name'),
+      ),
+    ),
+  );
   return $items;
 }
 
@@ -39,9 +62,11 @@ function rules_scheduler_action() {
   $element  = array_pop($args);
   $settings = array_pop($args);
 
+  $task_id = array_shift($args);
   $date = array_shift($args);
+  
+  array_shift($element['#info']['arguments']);
   array_shift($element['#info']['arguments']);
-
   $pack = rules_pack_variables($element['#info']['arguments'], $args);
 
   if ($pack === FALSE) {
@@ -52,6 +77,7 @@ function rules_scheduler_action() {
         'date' => $date,
         'set_name' => $element['#info']['set'],
         'arguments' => $pack,
+        'identifier' => $task_id,
       ));
   }
 }
@@ -63,3 +89,39 @@ function rules_scheduler_action_help() {
   return t("The evaluation of the rule set is going to be scheduled by cron. So make sure you have configured cron correctly by checking your site's !status.", array('!status' => l('Status report', 'admin/reports/status'))) .' '. t('Also note that the scheduling time accuracy depends on your configured cron interval.');
 }
 
+/**
+ * Action implementation for deleting already scheduled tasks
+ */
+function rules_scheduler_action_delete($task_identifier = NULL, $rule_set_name = NULL) {
+  if (!empty($rule_set_name)) {
+    if (!empty($task_identifier)) {
+      db_query("DELETE FROM {rules_scheduler} WHERE set_name = '%s' AND identifier = '%s'", $rule_set_name, $task_identifier);
+    }
+    else {
+      db_query("DELETE FROM {rules_scheduler} WHERE set_name = '%s'", $rule_set_name);
+    }
+  }
+  else {
+    if (!empty($task_identifier)) {
+      db_query("DELETE FROM {rules_scheduler} WHERE identifier = '%s'", $task_identifier);
+    }
+    else {
+      db_query("DELETE FROM {rules_scheduler}");
+    }
+  }
+}
+
+/**
+ * Changes the style of the action form.
+ */
+function rules_scheduler_action_delete_form($settings, &$form) {
+  $form['settings']['ruleset']['#type'] = 'select';
+  $select = array('' => '');
+  $select += drupal_map_assoc(array_keys(rules_get_configured_items('rule_sets')));
+  $form['settings']['ruleset']['#options'] = $select;
+  $form['settings']['ruleset']['#multiple'] = FALSE;
+  $form['settings']['ruleset']['#default_value'] = '';
+  $form['settings']['ruleset']['#required'] = FALSE;
+  
+  $form['settings']['task_identifier']['#required'] = FALSE;
+}
\ No newline at end of file
Index: rules_scheduler/rules_scheduler.views.inc
===================================================================
RCS file: rules_scheduler/rules_scheduler.views.inc
diff -N rules_scheduler/rules_scheduler.views.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ rules_scheduler/rules_scheduler.views.inc	3 Jul 2009 16:26:31 -0000
@@ -0,0 +1,19 @@
+<?php
+//$Id: $
+
+/**
+ * Implementation of hook_views_handlers().
+ */
+function rules_scheduler_views_handlers() {
+  return array(
+    'info' => array(
+      'path' => drupal_get_path('module', 'rules_scheduler'),
+    ),
+    // A handler for datetime
+    'handlers' => array(
+      'rules_scheduler_datetime' => array(
+        'parent' => 'views_handler_field_date',
+      ),
+     ),
+   );
+}
\ No newline at end of file
Index: rules_scheduler/rules_scheduler.views_default.inc
===================================================================
RCS file: rules_scheduler/rules_scheduler.views_default.inc
diff -N rules_scheduler/rules_scheduler.views_default.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ rules_scheduler/rules_scheduler.views_default.inc	3 Jul 2009 16:26:31 -0000
@@ -0,0 +1,196 @@
+<?php
+// $Id:$
+
+/**
+ * Implementation of hook_views_default_views().
+ */
+function rules_scheduler_views_default_views() {
+  $view = new view;
+  $view->name = 'rules_scheduler';
+  $view->description = 'Rules scheduler view';
+  $view->tag = '';
+  $view->view_php = '';
+  $view->base_table = 'rules_scheduler';
+  $view->is_cacheable = FALSE;
+  $view->api_version = 2;
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->override_option('fields', array(
+    'tid' => array(
+      'label' => 'Task ID',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'exclude' => 0,
+      'id' => 'tid',
+      'table' => 'rules_scheduler',
+      'field' => 'tid',
+      'relationship' => 'none',
+    ),
+    'set_name' => array(
+      'label' => 'Rule set name',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'exclude' => 0,
+      'id' => 'set_name',
+      'table' => 'rules_scheduler',
+      'field' => 'set_name',
+      'relationship' => 'none',
+    ),
+    'date' => array(
+      'label' => 'Scheduled date',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'date_format' => 'custom',
+      'custom_date_format' => 'Y-m-d H:i:s',
+      'exclude' => 0,
+      'id' => 'date',
+      'table' => 'rules_scheduler',
+      'field' => 'date',
+      'relationship' => 'none',
+    ),
+    'identifier' => array(
+      'label' => 'User provided identifier',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'exclude' => 0,
+      'id' => 'identifier',
+      'table' => 'rules_scheduler',
+      'field' => 'identifier',
+      'relationship' => 'none',
+    ),
+    'nothing' => array(
+      'label' => 'Operations',
+      'alter' => array(
+        'text' => 'delete',
+        'make_link' => 1,
+        'path' => 'admin/rules/rule_sets/scheduling/[tid]/delete',
+        'link_class' => '',
+        'alt' => 'Delete this scheduled task',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'exclude' => 0,
+      'id' => 'nothing',
+      'table' => 'views',
+      'field' => 'nothing',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('sorts', array(
+    'date' => array(
+      'order' => 'ASC',
+      'id' => 'date',
+      'table' => 'rules_scheduler',
+      'field' => 'date',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('access', array(
+    'type' => 'perm',
+    'perm' => 'administer rules',
+  ));
+  $handler->override_option('cache', array(
+    'type' => 'none',
+  ));
+  $handler->override_option('empty', 'No tasks scheduled.');
+  $handler->override_option('empty_format', '1');
+  $handler->override_option('items_per_page', 30);
+  $handler->override_option('style_plugin', 'table');
+  $handler->override_option('style_options', array(
+    'grouping' => '',
+    'override' => 1,
+    'sticky' => 0,
+    'order' => 'asc',
+    'columns' => array(
+      'set_name' => 'set_name',
+      'date' => 'date',
+      'tid' => 'tid',
+    ),
+    'info' => array(
+      'set_name' => array(
+        'sortable' => 1,
+        'separator' => '',
+      ),
+      'date' => array(
+        'sortable' => 1,
+        'separator' => '',
+      ),
+      'tid' => array(
+        'sortable' => 1,
+        'separator' => '',
+      ),
+    ),
+    'default' => '-1',
+  ));
+
+  $views = array();
+  $views[$view->name] = $view;
+  return $views;
+}
\ No newline at end of file
Index: rules_scheduler/rules_scheduler_datetime.inc
===================================================================
RCS file: rules_scheduler/rules_scheduler_datetime.inc
diff -N rules_scheduler/rules_scheduler_datetime.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ rules_scheduler/rules_scheduler_datetime.inc	3 Jul 2009 16:26:31 -0000
@@ -0,0 +1,22 @@
+<?php
+// $Id:$
+
+/**
+ * @file
+ * An extended subclass for datetime handling.
+ * We need this to correctly convert our SQL datetime field to local user date/time.
+ */
+class rules_scheduler_datetime extends views_handler_field_date {
+
+  function render($values) {
+    $value = $values->{$this->field_alias};
+    // convert to unix timestamp (int), local time
+    $value = strtotime($value);
+    // convert to GMT unix timestamp
+    $value = gmmktime(date('H', $value), date('i', $value), date('s', $value), date('n', $value), date('j', $value), date('Y', $value));
+    // overwrite date string with timestamp
+    $values->{$this->field_alias} = $value;
+    // call parent method with modified values
+    return parent::render($values);
+  }
+}
\ No newline at end of file
