### Eclipse Workspace Patch 1.0
#P CVS simplenews HEAD
Index: simplenews.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/simplenews/simplenews.module,v
retrieving revision 1.56
diff -u -r1.56 simplenews.module
--- simplenews.module	20 Feb 2007 18:47:01 -0000	1.56
+++ simplenews.module	14 Apr 2007 10:38:10 -0000
@@ -114,14 +114,20 @@
       'callback' => 'drupal_get_form',
       'callback arguments' => array('simplenews_admin_types_form'),
     );
-
+    $items[] = array(
+      'path' => 'admin/content/newsletters/subscriptions/delete',
+      'title' => t('Delete'),
+      'type' => MENU_CALLBACK,
+      'callback' => 'drupal_get_form',
+      'callback arguments' => 'simplenews_subscription_multiple_delete_confirm',
+      'access' => $administer,
+    );
     $items[] = array('path' => 'admin/content/newsletters/users',
       'title' => t('Subscriptions'),
       'access' => $administer,
       'type' => MENU_LOCAL_TASK,
       'weight' => -7,
-      'callback' => 'drupal_get_form',
-      'callback arguments' => array('simplenews_admin_list'),
+      'callback' => 'simplenews_admin_list',
     );
     $items[] = array('path' => 'admin/content/newsletters/users/edit',
       'title' => t('Subscriptions'),
@@ -160,19 +166,6 @@
       'callback arguments' => array('simplenews_admin_list_export'),
     );
 
-    $items[] = array('path' => 'admin/content/newsletters/users/activate',
-      'title' => t('Activate subscription'),
-      'access' => $administer,
-      'type' => MENU_CALLBACK,
-      'callback' => 'simplenews_activate_subscription',
-    );
-    $items[] = array('path' => 'admin/content/newsletters/users/inactivate',
-      'title' => t('Inactivate subscription'),
-      'access' => $administer,
-      'type' => MENU_CALLBACK,
-      'callback' => 'simplenews_inactivate_subscription',
-    );
-
     $items[] = array('path' => 'admin/content/newsletters/settings',
       'title' => t('Settings'),
       'access' => $administer,
@@ -395,7 +388,7 @@
   //since simplenews_cron() also calls _simplenews_send().
   $s_status = ($node->send == 1 && user_access('send newsletter')) ? 1 : 0;
   db_query("INSERT INTO {simplenews_newsletters} (nid, tid, s_status, s_format, priority, receipt)
-		  VALUES (%d, %d, %d, '%s', %d, %d)", $node->nid, $node->simplenews_tid, $s_status, $node->s_format, $node->priority, $node->receipt);
+      VALUES (%d, %d, %d, '%s', %d, %d)", $node->nid, $node->simplenews_tid, $s_status, $node->s_format, $node->priority, $node->receipt);
 }
 
 /**
@@ -407,7 +400,7 @@
   $node->simplenews_tid = $tid ? $tid[0] : 0;
   $s_status = ($node->send == 1 && user_access('send newsletter')) ? 1 : 0;
   db_query("UPDATE {simplenews_newsletters} SET tid = %d, s_status = %d, s_format = '%s', priority = %d, receipt = %d
-		  WHERE nid = %d", $node->simplenews_tid, $s_status, $node->s_format, $node->priority, $node->receipt, $node->nid);
+      WHERE nid = %d", $node->simplenews_tid, $s_status, $node->s_format, $node->priority, $node->receipt, $node->nid);
 }
 
 /**
@@ -1384,25 +1377,29 @@
 }
 
 /**
- * Menu callback; activates the specified subscription.
+ * Callback function to activate the specified subscriptions.
+ * 
+ * @param $snid array of snid's
  */
-function simplenews_activate_subscription($snid = NULL) {
-  if (isset($snid) && is_numeric($snid)) {
-    db_query('UPDATE {simplenews_subscriptions} SET a_status = 1 WHERE snid = %d', $snid);
-  }
-  drupal_goto('admin/content/newsletters/users');
+function simplenews_activate_subscription($snid) {
+  db_query('UPDATE {simplenews_subscriptions} SET a_status = 1 WHERE snid IN(%s)', implode(',', $snid));
 }
 
 /**
- * Menu callback; inactivates the specified subscription.
+ * Callback function to inactivate the specified subscriptions.
+ * 
+ * @param $snid array of snid's
  */
-function simplenews_inactivate_subscription($snid = NULL) {
-  if (isset($snid) && is_numeric($snid)) {
-    db_query('UPDATE {simplenews_subscriptions} SET a_status = 0 WHERE snid = %d', $snid);
-  }
-  drupal_goto('admin/content/newsletters/users');
+function simplenews_inactivate_subscription($snid) {
+  db_query('UPDATE {simplenews_subscriptions} SET a_status = 0 WHERE snid IN(%s)', implode(',', $snid));
 }
 
+/**
+ * Store filter values in session var
+ * 
+ * @param $type identification string
+ * @param $form_values array of values to be stored
+ */
 function simplenews_set_filter($type, $form_values) {
   if (empty($_SESSION[$type])) {
     $_SESSION[$type] = 'all';
@@ -1413,13 +1410,23 @@
   }
 }
 
+/**
+ * Built filter selection box options and filter query where clause
+ * 
+ * @param $type identification string
+ * @param $na TRUE for orphaned newsletters
+ * 
+ * @return array of filter selection box options and related query where clause
+ */
 function simplenews_get_filter($type, $na = TRUE) {
+  //Default data
   $names['all'] = t('all newsletters');
   $queries['all'] = '';
   if ($na) {
     $names['na'] = t('orphaned newsletters');
     $queries['na'] = ' AND s.tid = 0';
   }
+  // Data for each newsletter
   foreach (taxonomy_get_tree(_simplenews_get_vid()) as $newsletter) {
     $names[$newsletter->tid] = $newsletter->name;
     $queries[$newsletter->tid] = ' AND s.tid = '. $newsletter->tid;
@@ -1474,22 +1481,12 @@
   if (!$rows) {
     $rows[] = array(array('data' => t('No newsletters available.'), 'colspan' => '6'));
   }
-  else {
-    $key_table = TRUE;
-  }
   $form['simplenews_issue_filter']['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Filter'),
   );
 
   $table = theme('table', $header, $rows);
-  if ($key_table) {
-    $key_header = array(array('data' => t('Table key'), 'colspan' => '2'));
-    $key_rows[] = array(theme('simplenews_status', 0, 'sent'), t('Not published/Not sent'));
-    $key_rows[] = array(theme('simplenews_status', 2, 'sent'), t('Published/Sent'));
-    $key_rows[] = array(theme('simplenews_status', 1, 'sent'), t('Currently sending by cron'));
-    $table .= theme('table', $key_header, $key_rows);
-  }
 
   $form['table'] = array('#value' => $table);
   return $form;
@@ -1500,75 +1497,311 @@
 }
 
 function theme_simplenews_status($status, $source) {
-  if ($source == 'published') {
-    $imgs = array(0 => 'sn-saved', 1 => 'sn-sent');
-  }
-  elseif ($source == 'sent') {
-    $imgs = array(0 => 'sn-saved', 1 => 'sn-cron', 2 => 'sn-sent');
+  switch ($source) {
+    case 'published':
+      $imgs = array(0 => 'sn-saved', 1 => 'sn-sent');
+      $title = array(0 => t('Not published'), 1 => t('Published'));
+      break;
+    case 'activated':
+      $imgs = array(0 => 'sn-saved', 1 => 'sn-sent');
+      $title = array(0 => t('Inactive: no newsletters will be sent'), 1 => t('Active: user will receive newsletters'));
+      break;
+    case 'sent':
+      $imgs = array(0 => 'sn-saved', 1 => 'sn-cron', 2 => 'sn-sent');
+      $title = array(0 => t('Not sent'), 1 => t('Currently sending by cron'), 2 => t('Sent'));
+      break;
   }
   $path = base_path() . drupal_get_path('module', 'simplenews') .'/';
-  $output = '<img src="'. $path . $imgs[$status] .'.png" width="15" height="15" alt="'. $status .'" border="0" />';
+  $output = '<img src="'. $path . $imgs[$status] .'.png" width="15" height="15" alt="'. $status .'" border="0" title="'. $title[$status] .'" />';
   return $output;
 }
 
-function simplenews_admin_list() {
-  list($names, $queries) = array_values(simplenews_get_filter('simplenews_subscriptions_filter', FALSE));
-  $form['simplenews_subscriptions_filter'] = array(
+/**
+ * Generate subscription filters
+ */
+function simplenews_subscription_filters() {
+  // Newsletter filter
+  $filters['newsletter'] = array(
+    'title' => t('Subscribed to'),
+    'options' => array(
+      'all'   => t('All newsletters'),
+    ),
+  );
+  foreach (taxonomy_get_tree(_simplenews_get_vid()) as $newsletter) {
+    $filters['newsletter']['options']['tid-'. $newsletter->tid] = $newsletter->name;
+  }
+  
+  // E-mail filter
+  $filters['email'] = array (
+    'title' => t('E-mail address'),
+  );
+  
+  return $filters;
+}
+
+/**
+ * Build query for subscription filters based on session var content. 
+ * 
+ * @return array of SQL query parts 
+ *   array('where' => $where, 'join' => $join, 'args' => $args)
+ */
+function simplenews_build_subscription_filter_query() {
+  // Variables $args and $join are currently not used but left in for future extensions
+  $where = $args = array();
+  $join = '';
+  
+  // Build query
+  foreach ($_SESSION['simplenews_subscriptions_filter'] as $key => $value) {
+  switch ($key) {
+      case 'newsletter':
+        list($key, $value) = explode('-', $value, 2);
+        if ($key != 'all') {
+          $where[] = 's.'. $key .' = '. $value;
+        } 
+        break;
+      case 'email':
+        if (!empty($value)) {
+          $where[] = 'ss.mail LIKE "%%'. db_escape_string($value) .'%%"';
+        }
+        break;
+    }
+    $args[] = $value;
+  }
+
+  // All conditions are combined with AND
+  $where = empty($where) ? '' : ' AND '. implode(' AND ', $where);
+ 
+  return array('where' => $where, 'join' => $join, 'args' => $args);
+}
+
+/**
+ * Return form for subscription filters.
+ */
+function simplenews_subscription_filter_form() {
+  // Current filter selections in $session var; stored at form submission
+  // Example: array('newsletter' => 'all', 'email' => 'hotmail')
+  $session = &$_SESSION['simplenews_subscriptions_filter'];
+  $session = is_array($session) ? $session : _simplenews_subscription_filter_default();
+  $filters = simplenews_subscription_filters();
+
+  $form['filters'] = array(
     '#type' => 'fieldset',
-    '#title' => t('Show subscriptions to'),
+    '#title' => t('Subscription filters'),
     '#collapsible' => FALSE,
-    '#prefix' => '<div class="container-inline">',
+    '#prefix' => '<div class="simplenews-subscription-filter">',
     '#suffix' => '</div>',
   );
-  $form['simplenews_subscriptions_filter']['filter'] = array(
+  
+  // Filter values are default
+  $form['filters']['newsletter'] = array(
     '#type' => 'select',
-    '#options' => $names,
-    '#default_value' => $_SESSION['simplenews_subscriptions_filter'],
+    '#title' => $filters['newsletter']['title'],
+    '#options' => $filters['newsletter']['options'],
+    '#default_value' => $session['newsletter'],
+  );
+  $form['filters']['email'] = array(
+    '#type' => 'textfield',
+    '#title' => $filters['email']['title'],
+    '#default_value' => $session['email'],
   );
-  $form['simplenews_subscriptions_filter']['submit'] = array(
+  $form['filters']['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Filter'),
+    '#prefix' => '<span class="spacer" />',
   );
-  $header = array(NULL, t('E-mail'), t('Username'), t('Status'), array('data' => t('Operations'), 'colspan' => '3'));
-  $query = 'SELECT DISTINCT ss.*, u.name FROM {simplenews_subscriptions} ss INNER JOIN {users} u ON ss.uid = u.uid INNER JOIN {simplenews_snid_tid} s ON ss.snid = s.snid'. $queries[$_SESSION['simplenews_subscriptions_filter']].' ORDER BY ss.mail ASC';
-  $count_query = 'SELECT COUNT(DISTINCT(ss.snid)) FROM {simplenews_subscriptions} ss INNER JOIN {simplenews_snid_tid} s ON ss.snid = s.snid'. $queries[$_SESSION['simplenews_subscriptions_filter']];
-  $result = pager_query($query, 15, 0, $count_query);
-  if ($_GET['page']) {
-    $i = (int) $_GET['page'] * 15;
+  // Add Reset button if filter is in use
+  if ($session != _simplenews_subscription_filter_default()) {
+    $form['filters']['reset'] = array(
+      '#type' => 'submit', 
+      '#value' => t('Reset')
+    );
+  }
+  
+  return $form;
+}
+
+/**
+ * Helper function: returns subscription filter default settings
+ */
+function _simplenews_subscription_filter_default() {
+  return array('newsletter' => 'all', 'email' => '');
+}
+
+function simplenews_subscription_filter_form_submit($form_id, $form_values) {
+  switch ($form_values['op']) {
+    case t('Filter'):
+      $_SESSION['simplenews_subscriptions_filter'] = array(
+        'newsletter' => $form_values['newsletter'],
+        'email' => $form_values['email'],
+      );
+      break;
+    case t('Reset'):
+      $_SESSION['simplenews_subscriptions_filter'] = _simplenews_subscription_filter_default();
+      break;
   }
+}
+
+/**
+ * Menu callback: subscription administration.
+ */
+function simplenews_admin_list() {
+  drupal_add_css(drupal_get_path('module', 'simplenews') .'/simplenews.css', 'module', 'all', FALSE);
+  
+  // Deleting subscriptions requires delete confirmation. This is handled with a different form
+  if ($_POST['operation'] == 'delete' && $_POST['snids']) {
+    if ($_REQUEST['destination']) {
+      $destination = drupal_get_destination();
+      unset($_REQUEST['destination']);
+    }
+    $_SESSION['simplenews_subscriptions_delete'] = $_POST['snids'];
+    // Note: we redirect from admin/content/newsletters/users to admin/content/newsletters/subscriptions/delete to make the tabs disappear.
+    drupal_goto("admin/content/newsletters/subscriptions/delete", $destination);  
+  }
+
+  // Call the filter form first, to allow for the form_values array to be populated.
+  $output = drupal_get_form('simplenews_subscription_filter_form');
+  $output .= drupal_get_form('simplenews_admin_list_form');
+
+  return $output;
+}
+
+function simplenews_admin_list_form() {
+  global $form_values;
+
+  $filter = simplenews_build_subscription_filter_query();
+  $query = 'SELECT DISTINCT ss.*, u.name FROM {simplenews_subscriptions} ss INNER JOIN {users} u ON ss.uid = u.uid INNER JOIN {simplenews_snid_tid} s ON ss.snid = s.snid'. $filter['where'].' ORDER BY ss.mail ASC';
+  $result = pager_query($query, 30, 0, NULL);
+  
+  $form['options'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Update options'),
+    '#prefix' => '<div class="container-inline">',
+    '#suffix' => '</div>',
+  );
+  $form['options']['operation'] = array(
+    '#type' => 'select', 
+    '#options' => array (
+      'activate' => 'Activate',
+      'inactivate' => 'Inactivate',
+      'delete' => 'Delete',
+    ),  
+    '#default_value' => 'activate');
+  $form['options']['submit'] = array(
+    '#type' => 'submit', 
+    '#value' => t('Update')
+  );
+
+  $destination = drupal_get_destination();
   while ($subs = db_fetch_object($result)) {
-    $key_table = TRUE;
-    $i++;
-    if ($subs->uid == 0) {
-      $subs->name = t('Unregistered user');
-    }
-    if ($subs->a_status == 0) {
-      $activate = l(t('activate'), 'admin/content/newsletters/users/activate/'. $subs->snid);
-    }
-    elseif ($subs->a_status == 1) {
-      $activate = l(t('inactivate'), 'admin/content/newsletters/users/inactivate/'. $subs->snid);
+    $snids[$subs->snid] = '';
+    $form['mail'][$subs->snid] = array('#value' => $subs->mail);
+    $form['name'][$subs->snid] =  array('#value' => $subs->uid ? l($subs->name, 'user/'. $subs->uid) : $subs->name);
+    $form['status'][$subs->snid] = array('#value' => theme('simplenews_status', $subs->a_status, 'activated'));
+    $form['operations'][$subs->snid] = array('#value' => l(t('edit'), 'admin/content/newsletters/users/edit/'. $subs->snid, array(), drupal_get_destination()));
+      }
+  $form['snids'] = array('#type' => 'checkboxes', '#options' => $snids);
+  $form['pager'] = array('#value' => theme('pager', NULL, 30, 0));
+  return $form;
+}
+
+function simplenews_admin_list_form_validate($form_id, $form_values) {
+  if (isset($form_values['operation'])) {
+    $snids = array_filter($form_values['snids']);
+    if (empty($snids)) {
+      form_set_error('', t('No items selected.'));
     }
-    $rows[] = array($i, $subs->mail, ($subs->uid ? l($subs->name, 'user/'. $subs->uid) : $subs->name), theme('simplenews_status', $subs->a_status, 'published'), l(t('edit'), 'admin/content/newsletters/users/edit/'. $subs->snid, array(), drupal_get_destination()),l(t('delete'), 'admin/content/newsletters/users/delete/'. $subs->snid), $activate);
   }
-  if ($pager = theme('pager', NULL, 15, 0)) {
-    $rows[] = array(array('data' => $pager, 'colspan' => '7'));
+}
+
+/**
+ * Submit the subscription administration update form.
+ */
+function simplenews_admin_list_form_submit($form_id, $form_values) {
+  if (isset($form_values['operation'])) {
+    $snids = array_filter($form_values['snids']);
+    $args = array($snids);
+    switch ($form_values['operation']) {
+      case 'activate':
+        call_user_func_array('simplenews_activate_subscription', $args);
+        drupal_set_message(t('The update has been performed.'));
+        break;
+      case 'inactivate':
+        call_user_func_array('simplenews_inactivate_subscription', $args);
+        drupal_set_message(t('The update has been performed.'));
+        break;
+    }
   }
-  if (!$rows) {
-    $rows[] = array(array('data' => t('No subscriptions available.'), 'colspan' => '7'));
+}
+
+/**
+ * Theme subscription administration overview.
+ */
+function theme_simplenews_admin_list_form($form) {
+  // Overview table:
+  $header = array(theme('table_select_header_cell'), t('E-mail'), t('Username'), t('Status'), t('Operations'));
+  
+  $output .= drupal_render($form['options']);
+  if (isset($form['mail']) && is_array($form['mail'])) {
+    foreach (element_children($form['mail']) as $key) {
+      $row = array();
+      $row[] = drupal_render($form['snids'][$key]);
+      $row[] = drupal_render($form['mail'][$key]);
+      $row[] = drupal_render($form['name'][$key]);
+      $row[] = drupal_render($form['status'][$key]);
+      $row[] = drupal_render($form['operations'][$key]);
+      $rows[] = $row;
+    }
+  }
+  else  {
+    $rows[] = array(array('data' => t('No subscriptions available.'), 'colspan' => '4'));
+  }
+
+  $output .= theme('table', $header, $rows);
+  if ($form['pager']['#value']) {
+    $output .= drupal_render($form['pager']);
   }
-  $table = theme('table', $header, $rows);
-  if ($key_table) {
-    $key_header = array(array('data' => t('Table key'), 'colspan' => '2'));
-    $key_rows[] = array(theme('simplenews_status', 0, 'published'), t('Inactive/No newsletters will be sent'));
-    $key_rows[] = array(theme('simplenews_status', 1, 'published'), t('Active/User will receive newsletters'));
-    $table .= theme('table', $key_header, $key_rows);
+
+  $output .= drupal_render($form);
+
+  return $output;
+}
+
+/**
+ * Delete multiple subscriptions
+ */
+function simplenews_subscription_multiple_delete_confirm() {
+  // Subscriptions to be deleted are passed via session var.
+  $snids = $_SESSION['simplenews_subscriptions_delete'];
+  
+  $form['snids'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
+  // array_filter returns only elements with TRUE values
+  foreach (array_filter($snids) as $snid => $value) {
+    $mail = db_result(db_query('SELECT mail FROM {simplenews_subscriptions} WHERE snid = %d', $snid));
+    $form['snids'][$snid] = array(
+      '#type' => 'hidden', 
+      '#value' => $snid, 
+      '#prefix' => '<li>', 
+      '#suffix' => check_plain($mail) ."</li>\n"
+    );
   }
-  $form['table'] = array('#value' => $table);
-  return $form;
+  $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
+   
+  return confirm_form($form,
+                      t('Are you sure you want to delete these subscriptions?'),
+                      'admin/content/newsletters/users', t('This action cannot be undone.'),
+                      t('Delete all'), t('Cancel'));
 }
 
-function simplenews_admin_list_submit($form_id, $form_values) {
-  simplenews_set_filter('simplenews_subscriptions_filter', $form_values);
+function simplenews_subscription_multiple_delete_confirm_submit($form_id, $form_values) {
+  if ($form_values['confirm']) {
+    foreach ($form_values['snids'] as $snid => $value) {
+      simplenews_delete_subscription($snid);
+    }
+    drupal_set_message(t('The subscriptions have been deleted.'));
+  }
+
+  // Route the user back to the subscription admin form 
+  return 'admin/content/newsletters/users';
 }
 
 function simplenews_admin_list_add() {
Index: simplenews.css
===================================================================
RCS file: simplenews.css
diff -N simplenews.css
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ simplenews.css	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,19 @@
+.simplenews-subscription-filter .form-item { 
+  clear: both;
+  line-height:1.75em;
+  margin:0pt 1em 0pt 0pt;
+}
+
+.simplenews-subscription-filter .form-item label { 
+  float: left;
+  width: 12em; 
+}
+
+.simplenews-subscription-filter .spacer {
+  margin-left: 12em;  
+}
+
+.simplenews-subscription-filter .form-select, .simplenews-subscription-filter .form-text {
+  width: 14em;
+}
+
