#371861 by Berdir, nbz | litwol: Added feature to flush deleted messages.
authorSascha Grossenbacher
Sat, 10 Oct 2009 08:04:48 +0000 (08:04 +0000)
committerSascha Grossenbacher
Sat, 10 Oct 2009 08:04:48 +0000 (08:04 +0000)
privatemsg.api.php
privatemsg.install
privatemsg.module
privatemsg.test

index dcdeb5b..8563ecb 100644 (file)
@@ -279,22 +279,6 @@ function hook_privatemsg_message_load($message) {
 }
 
 /**
- * Is called when a message is deleted.
- *
- * Note: The message is actually only marked as deleted and only for the current
- * user.
- * @todo There is no "undelete" hook
- *
- * @param $pmid
- *   ID of the message that has been deleted
-  * @param $deleted_by_all
- *   Boolean to show whether the message has been deleted by all users or not
- */
-function hook_privatemsg_message_delete($pmid, $deleted_by_all) {
-
-}
-
-/**
  * Is called when a message is flushed.
  *
  * The message will be deleted from the database, remove any related data here.
index 3ab2cc9..5e156a7 100644 (file)
@@ -459,4 +459,16 @@ function privatemsg_update_6005() {
   $ret = array();
   $ret[] = update_sql("UPDATE {permission} SET perm = REPLACE(perm, 'read privatemsg', 'read privatemsg, delete privatemsg') WHERE perm LIKE '%read privatemsg%'");
   return $ret;
+}
+
+/**
+ * Set the deleted timestamp of all messages to now.
+ */
+function privatemsg_update_6006() {
+  $ret = array();
+
+  $sql = "UPDATE {pm_index} SET deleted = %d WHERE deleted = 1";
+  $result = db_query($sql, time());
+  $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql));
+  return $ret;
 }
\ No newline at end of file
index 872cac7..e9c939a 100644 (file)
@@ -390,6 +390,38 @@ function private_message_settings() {
     '#default_value' => variable_get('privatemsg_display_loginmessage', TRUE),
     '#description' => t('This option can safely be disabled if the "New message indication" block is used instead.'),
   );
+
+  $form['flush_deleted'] = array(
+    '#type'        => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed'   => TRUE,
+    '#title'       => t('Flush deleted messages'),
+    '#description' => t('By default, deleted messages are only hidden from the
+                         user but still stored in the database. These settings
+                         control if and when messages should be removed.'),
+  );
+
+  $form['flush_deleted']['privatemsg_flush_enabled'] = array(
+    '#type'          => 'checkbox',
+    '#title'         => t('Flush deleted messages'),
+    '#default_value' => variable_get('privatemsg_flush_enabled', FALSE),
+    '#description'   => t('Enable the flushing of deleted messages. Requires that cron is enabled'),
+  );
+
+  $form['flush_deleted']['privatemsg_flush_days'] = array(
+    '#type' => 'select',
+    '#title' => t('Flush messages after they have been deleted for more days than'),
+    '#default_value' => variable_get('privatemsg_flush_days', 30),
+    '#options' => drupal_map_assoc(array(0, 1, 2, 5, 10, 30, 100)),
+  );
+
+  $form['flush_deleted']['privatemsg_flush_max'] = array(
+    '#type' => 'select',
+    '#title' => t('Maximum number of messages to flush per cron run'),
+    '#default_value' => variable_get('privatemsg_flush_max', 200),
+    '#options' => drupal_map_assoc(array(50, 100, 200, 500, 1000)),
+  );
+
   $form['privatemsg_listing'] = array(
     '#type' => 'fieldset',
     '#title' => t('Configure listings'),
@@ -417,6 +449,31 @@ function private_message_settings_submit() {
   drupal_rebuild_theme_registry();
 }
 
+/**
+ * Implementation of hook_cron().
+ *
+ * If the flush feature is enabled, a given amount of deleted messages that are
+ * old enough are flushed.
+ */
+function privatemsg_cron() {
+  if (variable_get('privatemsg_flush_enabled', FALSE)) {
+    $query = _privatemsg_assemble_query('deleted', variable_get('privatemsg_flush_days', 30));
+    $result = db_query($query['query']);
+
+    $flushed = 0;
+    while (($row = db_fetch_array($result)) && ($flushed < variable_get('privatemsg_flush_max', 200))) {
+      $message = _privatemsg_load($row['mid']);
+      module_invoke_all('privatemsg_message_flush', $message);
+
+      // Delete recipients of the message.
+      db_query('DELETE FROM {pm_index} WHERE mid = %d', $row['mid']);
+      // Delete message itself.
+      db_query('DELETE FROM {pm_message} WHERE mid = %d', $row['mid']);
+      $flushed++;
+    }
+  }
+}
+
 function privatemsg_theme() {
   return array(
     'privatemsg_view'    => array(
@@ -1117,6 +1174,30 @@ function privatemsg_sql_autocomplete(&$fragments, $search, $names) {
 }
 
 /**
+ * Query Builder function to load all messages that should be flushed.
+ *
+ * @param $fragments
+ *   Query fragments array.
+ * @param $days
+ *   Select messages older than x days.
+ */
+function privatemsg_sql_deleted(&$fragments, $days) {
+  $fragments['primary_table'] = '{pm_message} pm';
+
+  $fragments['select'][] = 'pm.mid';
+  $fragments['select'][] = 'MIN(pmi.deleted) as is_deleted';
+  $fragments['select'][] = 'MAX(pmi.deleted) as last_deleted';
+
+  $fragments['inner_join'][] = 'INNER JOIN {pm_index} pmi ON (pmi.mid = pm.mid)';
+
+  $fragments['group_by'][] = 'pm.mid';
+
+  $fragments['having'][] = 'MIN(pmi.deleted) > 0';
+  $fragments['having'][] = 'MAX(pmi.deleted) < %d';
+  $fragments['query_args']['having'][] = time() - $days * 86400;
+}
+
+/**
  * @}
  */
 
@@ -1304,23 +1385,18 @@ function privatemsg_delete_submit($form, &$form_state) {
  * @ingroup api
  */
 function privatemsg_message_change_delete($pmid, $delete, $account = NULL) {
+  $delete_value = 0;
+  if ($delete == TRUE) {
+    $delete_value = time();
+  }
+
   if ($account){
-    db_query('UPDATE {pm_index} SET deleted = %d WHERE mid = %d AND uid = %d', $delete, $pmid, $account->uid);
+    db_query('UPDATE {pm_index} SET deleted = %d WHERE mid = %d AND uid = %d', $delete_value, $pmid, $account->uid);
   }
   else {
     // Mark deleted for all users.
-    db_query('UPDATE {pm_index} SET deleted = %d WHERE mid = %d', $delete, $pmid);
+    db_query('UPDATE {pm_index} SET deleted = %d WHERE mid = %d', $delete_value, $pmid);
   }
-
-  $result = db_query("SELECT MIN(deleted) AS deleted_by_all FROM {pm_index} WHERE mid = %d", $pmid);
-  $deleted = db_fetch_array($result);
-
-  $deleted_by_all = FALSE;
-  if ($deleted['deleted_by_all'] > 0) {
-    $deleted_by_all = TRUE;
-  }
-
-  module_invoke_all('privatemsg_message_delete', $pmid, $deleted_by_all);
 }
 
 /**
index 2ab1e55..78a600d 100644 (file)
@@ -110,6 +110,58 @@ class PrivatemsgTestCase extends DrupalWebTestCase {
     }
   }
 
+  /**
+   * Tests for the flush feature
+   */
+  function testPrivatemsgFlush()
+  {
+    $author = $this->drupalCreateUser(array('write privatemsg', 'read privatemsg'));
+    $recipient = $this->drupalCreateUser(array('write privatemsg', 'read privatemsg'));
+
+    // Send 10 messages.
+    for ($i = 0; $i < 10; $i++) {
+      privatemsg_new_thread(array($recipient), 'Message #'. $i, 'This is the body', array('author' => $author));
+    }
+
+    // Delete message 1, 3, 4, 6, 9 for author.
+    foreach (array(1, 3, 4, 6, 9) as $pmid) {
+      privatemsg_message_change_delete($pmid, TRUE, $author);
+    }
+
+    // Delete message 1, 2, 4, 6, 8 for recipient.
+    foreach (array(1, 3, 4, 6, 9) as $pmid) {
+      privatemsg_message_change_delete($pmid, TRUE, $recipient);
+    }
+
+    // Now, mid 1, 4 and 6 have been deleted by both.
+
+    // Flush configuration, enable, delay is default, 30 days
+    variable_set('privatemsg_flush_enabled', TRUE);
+
+    // Set back the deleted timestamp 35 days back of mid 4.
+    db_query('UPDATE {pm_index} SET deleted = %d WHERE mid = 4',  time() - 35 * 86400);
+    // Set back the deleted timestamp of mid 6, but only 20 back.
+    db_query('UPDATE {pm_index} SET deleted = %d WHERE mid = 6', time() - 20 * 86400);
+
+    // Run flush.
+    privatemsg_cron();
+
+    // Check if the undeleted messages are still there.
+    foreach (array(2, 3, 5, 7, 8, 9, 10) as $pmid) {
+      $message = _privatemsg_load($pmid, $author);
+      $this->assertTrue(!empty($message), t('Undeleted message #%id is still in the system', array('%id' => $pmid)));
+    }
+
+    // Check if the "recently" deleted  messages are still there.
+    foreach (array(1, 6) as $pmid) {
+      $message = _privatemsg_load($pmid, $author);
+      $this->assertTrue(!empty($message), t('Deleted message #%id is still in the system', array('%id' => $pmid)));
+    }
+
+    // Mid 4 should have been flushed.
+    $message = _privatemsg_load(4, $author);
+    $this->assertTrue(empty($message), t('Message #4 has been flushed'));
+  }
 
   /**
    * Implementation of tearDown().