? invite-DRUPAL-4-7-delete.patch
Index: invite.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/invite/Attic/invite.install,v
retrieving revision 1.2.2.4
diff -u -r1.2.2.4 invite.install
--- invite.install	16 Jan 2007 10:12:48 -0000	1.2.2.4
+++ invite.install	19 Feb 2007 01:25:42 -0000
@@ -11,35 +11,39 @@
       $result1 = db_query("
         CREATE TABLE {invite} (
           email varchar(64) NOT NULL default '',
-          reg_code varchar(64) UNIQUE NOT NULL,
+          reg_code varchar(64) NOT NULL default '',
           uid int(10) unsigned NOT NULL default '0',
-          mid int(11) unsigned NOT NULL default '0',
+          mid int(10) unsigned NOT NULL default '0',
           expiry int(11) NOT NULL default '0',
           timestamp int(11) NOT NULL default '0',
-          received int(11) unsigned NOT NULL default '0',
-          PRIMARY KEY  (email)
+          received tinyint(3) unsigned NOT NULL default '0',
+          PRIMARY KEY  (email),
+          UNIQUE (reg_code)
         ) /*!40100 DEFAULT CHARACTER SET utf8 */;"
       );
-      $result2 = db_query("CREATE INDEX reg_code_idx ON {invite} (reg_code)");
+      $result2 = db_query("ALTER TABLE {invite} ADD INDEX (uid)");
       break;
+
     case 'pgsql':
       $result1 = db_query("
         CREATE TABLE {invite} (
-          email VARCHAR(64) NOT NULL PRIMARY KEY,
-          reg_code VARCHAR(64) UNIQUE NOT NULL,
+          email VARCHAR(64) NOT NULL,
+          reg_code VARCHAR(64) NOT NULL,
           uid INTEGER NOT NULL DEFAULT 0,
           mid INTEGER NOT NULL DEFAULT 0,
           expiry INTEGER NOT NULL DEFAULT 0,
           timestamp INTEGER NOT NULL DEFAULT 0,
-          received INTEGER NOT NULL DEFAULT 0
+          received SMALLINT NOT NULL DEFAULT 0,
+          PRIMARY KEY (email),
+          UNIQUE (reg_code)
         );"
       );
-      $result2 = db_query("CREATE INDEX reg_code_idx ON {invite} (reg_code)");
+      $result2 = db_query("CREATE INDEX {invite}_uid_idx ON {invite} (uid)");
       break;
     } 
 
   if ($result1 && result2) {
-    drupal_set_message(t('The database schema for the invite module has been successfully updated'));
+    drupal_set_message(t('The database schema for the invite module has been successfully updated.'));
   }
   else {
     drupal_set_message(t('Problems occurred while updating the database schema for the invite module.'));
@@ -47,14 +51,50 @@
 }
 
 function invite_update_1() {
+  $ret = array();
   switch ($GLOBALS['db_type']) {
     case 'mysql':
     case 'mysqli':
-      $items[] = update_sql("ALTER TABLE {invite} CHANGE reg_code reg_code VARCHAR(64) UNIQUE NOT NULL");
-      db_query("CREATE INDEX reg_code_idx ON {invite} (reg_code)");
+      $ret[] = update_sql("ALTER TABLE {invite} CHANGE reg_code reg_code VARCHAR(64) UNIQUE NOT NULL");
+      $ret[] = update_sql("ALTER TABLE {invite} ADD INDEX reg_code_idx (reg_code)");
       break;
   }
-  return $items;
+  return $ret;
 }
 
+/**
+ * Drop duplicate index on reg_code. Add index for uid.
+ * Clean up invitations for deleted users.
+ */
+function invite_update_2() {
+  $ret = array();
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      $ret[] = update_sql("ALTER TABLE {invite} DROP INDEX reg_code_idx");
+      $ret[] = update_sql("ALTER TABLE {invite} ADD INDEX (uid)");
+      break;
+    case 'pgsql':
+      $ret[] = update_sql("DROP INDEX reg_code_idx");
+      $ret[] = update_sql("CREATE INDEX {invite}_uid_idx ON {invite} (uid)");
+      break;
+  }
+
+  // Clean up invitees
+  $result = db_query("SELECT i.uid AS referrer, i.email FROM {invite} i LEFT JOIN {users} u ON i.mid = u.uid WHERE u.uid IS NULL");
+  while ($invitee = db_fetch_object($result)) {
+    db_query("DELETE FROM {invite} WHERE email = '%s'", $invitee->email);
+    if (db_affected_rows()) {
+      $args = array('inviter' => user_load(array('uid' => $invitee->referrer)), 'email' => $invitee->email);
+      module_invoke_all('invite', 'cancel', $args);
+    }
+  }
+  // Clean up referrers
+  $result = db_query("SELECT DISTINCT i.uid FROM {invite} i LEFT JOIN {users} u ON i.uid = u.uid WHERE u.uid IS NULL");
+  while ($referrer = db_fetch_object($result)) {
+    db_query("DELETE FROM {invite} WHERE uid = %d", $referrer->uid);
+  }
+
+  return $ret;
+}
 
Index: invite.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/invite/Attic/invite.module,v
retrieving revision 1.9.2.20
diff -u -r1.9.2.20 invite.module
--- invite.module	16 Feb 2007 02:09:30 -0000	1.9.2.20
+++ invite.module	19 Feb 2007 01:39:33 -0000
@@ -346,7 +346,20 @@
         watchdog('invite', 'User '. check_plain($user->name) .' registration code failed', $link = NULL);
       }
       break;
-  }   
+
+    case 'delete':
+      // delete matching invitees
+      $result = db_query("SELECT uid AS referrer, email FROM {invite} WHERE mid = %d", $account->uid);
+      if ($invitee = db_fetch_object($result)) {
+        db_query("DELETE FROM {invite} WHERE email = '%s'", $invitee->email);
+        $inviter = user_load(array('uid' => $invitee->referrer));
+        $args = array('inviter' => $inviter, 'email' => $invitee->email);
+        module_invoke_all('invite', 'cancel', $args);
+      }
+      // delete matching referrers
+      db_query("DELETE FROM {invite} WHERE uid = %d", $account->uid);
+      break;
+  }
 }
 
 /**
@@ -378,25 +391,17 @@
   );
 
   $inc = 0;
-  $result = db_query("SELECT * from {invite} WHERE uid = %d",$user->uid);
+  $result = db_query("SELECT * FROM {invite} WHERE uid = %d", $user->uid);
   while ($invite = db_fetch_object($result)){
-    $expiry = $invite->expiry + (variable_get('invite_expiry', '30') * 24 * 60 * 60);
     if (!$invite->timestamp) {
-      $email_cell = $invite->email;
-      if ($expiry < time()) {
-        $status_cell = t('Expired');
-        $action_cell = l(t("Delete invitation"),'invite/delete/'.urlencode($invite->email));
-      }
-      else {
-        $status_cell = t('Pending');
-        $action_cell = l(t("Delete invitation"),'invite/delete/'.urlencode($invite->email));
-      }
+      $email_cell = check_plain($invite->email);
+      $status_cell = ($invite->expiry < time()) ? t('Expired') : t('Pending');
+      $action_cell = l(t('Delete invitation'), 'invite/delete/'.urlencode($invite->email));
     }
     else {
-      $account = user_load(array('mail' => $invite->email));
-      $email_cell = isset($account->uid) ? l($invite->email, 'user/'.$account->uid) : "<i>{$invite->email}</i>";
+      $email_cell = l($invite->email, 'user/'.$invite->mid);
       $status_cell = t('Joined');
-      $action_cell = (variable_get('invite_allow_join_delete', 0) && isset($account->uid)) ? l(t("Delete invitation"),'invite/delete/'.urlencode($invite->email)) : '&nbsp;';
+      $action_cell = variable_get('invite_allow_join_delete', 0) ? l(t('Delete invitation'), 'invite/delete/'.$invite->mid) : '&nbsp;';
     }
     $items[] = array($email_cell, $status_cell, $action_cell);
     $inc++;
@@ -484,27 +489,61 @@
   }
 }
 
-function invite_delete($email) {
+/**
+ * Delete an invitation.
+ *
+ * Handles deletion by user id or email address. Registered users should always be
+ * deleted by their user id, as they could have changed their email address.
+ */
+function invite_delete($arg) {
+    global $user;
+
+  if (is_numeric($arg)) {
+    // Delete by user id
+    $invite = db_fetch_object(db_query("SELECT email, uid FROM {invite} WHERE mid = %d", $arg));
+    $email = $invite->email;
+    $referrer = $invite->uid;
+  }
+  else {
+    // Delete by email address
+    $email = urldecode($arg); // $email = rawurldecode(urlencode($email));
+    $referrer = db_result(db_query("SELECT uid FROM {invite} WHERE email = '%s'", $email));
+  }
+
+  if ($email != '') {
+    // Check referrer
+    if ($referrer == $user->uid) {
+      if (_invite_delete($email)) {
+        drupal_set_message(t('Invitation to %email has been deleted.', array('%email' => check_plain($email))));
+      }
+      else {
+        drupal_set_message(t('Invitations to registered users cannot be deleted.'));
+      }
+      }
+      else {
+      watchdog('invite', t('Detected malicious attempt to delete an invitation.'), WATCHDOG_WARNING, l(t('view'), 'user/'. $user->uid));
+      }
+    }
+    drupal_goto('invite');
+  }
+  
+/**
+ * @{
+ * Module specific helper functions.
+ */
+function _invite_delete($email) {
   global $user;
-  $email = urldecode($email); // $email = rawurldecode(urlencode($email));
-  if ($email) {
-    $account = user_load(array('mail' => $email));
-    if (!isset($account->uid) || variable_get('invite_allow_join_delete', 0)) {
-      db_query("DELETE from {invite} WHERE email = '%s'", $email);
-      drupal_set_message(t('Invitation to %email has been deleted.', array('%email' => check_plain($email))));
+  if (variable_get('invite_allow_join_delete', 0) || !user_load(array('mail' => $email))) {
+    db_query("DELETE from {invite} WHERE email = '%s' AND uid = %d", $email, $user->uid);
+    if (db_affected_rows()) {
       $args = array('inviter' => $user, 'email' => $email);
       module_invoke_all('invite', 'cancel', $args);
-    }
-    else {
-      drupal_set_message(t('Could not delete invitation, because %email already joined the site.', array('%email' => check_plain($email))));
+      return TRUE;
     }
   }
-  drupal_goto('invite');
+  return FALSE;
 }
 
-/*
-* Module Specific Helper functions
-*/
 function _invite_check_invited($email, $uid) {
   global $user;
   
