? .git ? privatemsg_roles.patch Index: privatemsg.install =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.install,v retrieving revision 1.15 diff -u -p -r1.15 privatemsg.install --- privatemsg.install 4 Jan 2010 15:56:56 -0000 1.15 +++ privatemsg.install 15 Jan 2010 13:38:46 -0000 @@ -24,8 +24,8 @@ function privatemsg_schema() { 'not null' => TRUE, 'unsigned' => TRUE, ), - 'uid' => array( - 'description' => 'UID of either the author or the recipient', + 'recipient' => array( + 'description' => 'ID of the recipient object, typically user', 'type' => 'int', 'not null' => TRUE, 'unsigned' => TRUE, @@ -44,13 +44,20 @@ function privatemsg_schema() { 'not null' => TRUE, 'default' => 0 ), + 'type' => array( + 'description' => 'Type of recipient object', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => 'user' + ), ), 'indexes' => array( 'mid' => array('mid'), 'thread_id' => array('thread_id'), - 'uid' => array('uid'), - 'is_new' => array('mid', 'uid', 'is_new', ), + 'recipient' => array('recipient', 'type'), + 'is_new' => array('mid', 'recipient', 'type', 'is_new'), ), ); @@ -528,3 +535,29 @@ function privatemsg_update_6007() { return $ret; } + +/** + * Change schema to allow other recipients than single users. + */ +function privatemsg_update_6008() { + $ret = array(); + db_drop_index($ret, 'pm_index', 'uid'); + db_drop_index($ret, 'pm_index', 'is_new'); + db_change_field($ret, 'pm_index', 'uid', 'recipient', array( + 'description' => 'ID of the recipient object, typically user', + 'type' => 'int', + 'not null' => TRUE, + 'unsigned' => TRUE, + )); + db_add_field($ret, 'pm_index', 'type', array( + 'description' => 'Type of recipient object', + 'type' => 'varchar', + 'not null' => TRUE, + 'length' => '255', + 'default' => 'user' + ), array('indexes' => array( + 'recipient' => array('recipient', 'type'), + 'is_new' => array('mid', 'recipient', 'type', 'is_new') + ))); + return $ret; +} Index: privatemsg.module =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.module,v retrieving revision 1.116 diff -u -p -r1.116 privatemsg.module --- privatemsg.module 7 Jan 2010 10:17:05 -0000 1.116 +++ privatemsg.module 15 Jan 2010 13:38:47 -0000 @@ -28,6 +28,7 @@ function privatemsg_perm() { 'read all private messages', 'administer privatemsg settings', 'write privatemsg', + 'write privatemsg to roles', 'delete privatemsg', ); } @@ -66,6 +67,18 @@ function _privatemsg_generate_user_array return $participants; } +function _privatemsg_format_participant($account) { + if (!empty($account->name)) { + if (!isset($account->uid)) { + $account->uid = $account->recipient; + } + return theme('username', $account); + } + else { + return $account->{$account->type . '_name'}; + } +} + /** * Format an array of user objects. * @@ -89,7 +102,7 @@ function _privatemsg_format_participants $limited = TRUE; break; } - $to[] = theme('username', $account); + $to[] = _privatemsg_format_participant($account); } $limit_string = ''; @@ -279,8 +292,7 @@ function privatemsg_view_access($thread) * @return TRUE if user has disabled private messaging, FALSE otherwise */ function privatemsg_is_disabled(&$account) { - - if (!$account || !$account->uid) { + if (!$account || !isset($account->uid) || !$account->uid) { return FALSE; } @@ -338,12 +350,25 @@ function privatemsg_thread_load($thread_ $query = _privatemsg_assemble_query('participants', $thread_id); $participants = db_query($query['query']); $thread['participants'] = array(); + $exists = FALSE; while ($participant = db_fetch_object($participants)) { - $thread['participants'][$participant->uid] = $participant; + if ($participant->type == 'user' && $participant->recipient == $account->uid) { + $exists = TRUE; + } + $thread['participants'][$participant->type . '_' . $participant->recipient] = $participant; } $thread['read_all'] = FALSE; - if (!array_key_exists($account->uid, $thread['participants']) && privatemsg_user_access('read all private messages', $account)) { - $thread['read_all'] = TRUE; + if (!$exists) { + // Maybe the user is part of some other recipient type, call the hook. + foreach (module_implements('privatemsg_is_recipient') as $module) { + if (!$exists = module_invoke($module, 'privatemsg_is_recipient', $account, $thread['participants'])) { + break; + } + } + // Check $exists again. + if (!$exists && privatemsg_user_access('read all private messages', $account)) { + $thread['read_all'] = TRUE; + } } // Load messages returned by the messages query with privatemsg_message_load_multiple(). @@ -546,7 +571,7 @@ function privatemsg_preprocess_privatems $vars['mid'] = isset($message['mid']) ? $message['mid'] : NULL; $vars['thread_id'] = isset($message['thread_id']) ? $message['thread_id'] : NULL; $vars['author_picture'] = theme('user_picture', $message['author']); - $vars['author_name_link'] = theme('username', $message['author']); + $vars['author_name_link'] = _privatemsg_format_participant($message['author']); /** * @todo perhaps make this timestamp configurable via admin UI? */ @@ -594,8 +619,13 @@ function privatemsg_message_change_statu global $user; $account = $user; } - $query = "UPDATE {pm_index} SET is_new = %d WHERE mid = %d AND uid = %d"; + $query = "UPDATE {pm_index} SET is_new = %d WHERE mid = %d AND recipient = %d AND type = 'user'"; db_query($query, $status, $pmid, $account->uid); + if (db_affected_rows() == 0) { + $message = privatemsg_message_load($pmid); + $index_sql = "INSERT INTO {pm_index} (mid, thread_id, recipient, type, is_new, deleted) VALUES (%d, %d, %d, '%s', %d, %d)"; + db_query($index_sql, $pmid, $message['thread_id'], $account->uid, 'user', 0, 0); + } } /** @@ -629,9 +659,14 @@ function _privatemsg_load_thread_partici $query = _privatemsg_assemble_query('participants', $thread_id); $result = db_query($query['query']); $participants = array(); - while ($uid = db_fetch_object($result)) { - if (($recipient = user_load($uid->uid))) { - $participants[$recipient->uid] = $recipient; + while ($participant = db_fetch_object($result)) { + if ($participant->type == 'user' && ($account = user_load($participant->recipient))) { + $participants['user_' . $account->uid] = $account; + } + elseif ($participant->type != 'user') { + // They key is always recipient. + $participant->key = 'recipient'; + $participants[$participant->type . '_' . $participant->recipient] = $participant; } } return $participants; @@ -666,8 +701,14 @@ function _privatemsg_parse_userstring($i foreach (module_implements('privatemsg_name_lookup') as $module) { $function = $module . '_privatemsg_name_lookup'; if (($recipient = $function($string)) && is_object($recipient)) { + // Default to user object. + if (!isset($recipient->type)) { + $recipient->type = 'user'; + $recipient->key = 'uid'; + } + $recipients[$recipient->{$recipient->key}] = $recipient; + // If there is a match, continue with the next input string. - $recipients[$recipient->uid] = $recipient; continue 2; } } @@ -686,6 +727,28 @@ function _privatemsg_parse_userstring($i return array($recipients, $invalid); } +function _privatemsg_build_where_clause($account) { + // Default parts. + $where = "pmi.recipient = %d AND pmi.type = 'user'"; + $args = $account->uid; + + // Fetch parts from other modules and merge defaults in. + $query_parts = module_invoke_all('privatemsg_recipients_where', $account); + if (!isset($query_parts['where'])) { + $query_parts['where'] = array(); + } + if (!isset($query_parts['args'])) { + $query_parts['args'] = array(); + } + array_unshift($query_parts['where'], $where); + array_unshift($query_parts['args'], $args); + + // Merge the different where parts in a single string, splitted by OR. + $query_parts['where'] = '(' . implode(') OR (', $query_parts['where']) . ')'; + + return $query_parts; +} + /** * @addtogroup sql * @{ @@ -717,8 +780,10 @@ function privatemsg_sql_list(&$fragments $fragments['select'][] = 'MIN(pm.subject) as subject'; $fragments['select'][] = 'MAX(pm.timestamp) as last_updated'; // We use SUM so that we can count the number of unread messages. - $fragments['select'][] = 'SUM(pmi.is_new) as is_new'; - + $read_messages = "(SELECT COUNT(DISTINCT pmi.mid) FROM {pm_index} pmie WHERE pmie.mid = pmi.mid AND pmie.recipient = %d AND pmie.is_new = 0 AND pmie.type = 'user' LIMIT 1)"; + $fragments['select'][] = "(COUNT(DISTINCT pmi.mid) - IF ($read_messages IS NULL, 0, $read_messages)) AS is_new"; + $fragments['query_args']['select'][] = $account->uid; + $fragments['query_args']['select'][] = $account->uid; // Select number of messages in the thread if the count is // set to be displayed. if (in_array('count', $fields)) { @@ -729,14 +794,14 @@ function privatemsg_sql_list(&$fragments // @todo: Replace this with a single query similiar to the tag list. if ($GLOBALS['db_type'] == 'pgsql') { // PostgreSQL does not know GROUP_CONCAT, so a subquery is required. - $fragments['select'][] = "array_to_string(array(SELECT DISTINCT textin(int4out(pmia.uid)) + $fragments['select'][] = "array_to_string(array(SELECT DISTINCT textin(int4out(pmia.recipient)) FROM {pm_index} pmia - WHERE pmia.thread_id = pmi.thread_id), ',') AS participants"; + WHERE pmia.type = 'user' AND pmia.thread_id = pmi.thread_id), ',') AS participants"; } else { - $fragments['select'][] = '(SELECT GROUP_CONCAT(DISTINCT pmia.uid SEPARATOR ",") + $fragments['select'][] = "(SELECT GROUP_CONCAT(DISTINCT pmia.recipient SEPARATOR ',') FROM {pm_index} pmia - WHERE pmia.thread_id = pmi.thread_id) AS participants'; + WHERE pmia.type = 'user' AND pmia.thread_id = pmi.thread_id) AS participants"; } } if (in_array('thread_started', $fields)) { @@ -745,9 +810,12 @@ function privatemsg_sql_list(&$fragments $fragments['inner_join'][] = 'INNER JOIN {pm_index} pmi ON pm.mid = pmi.mid'; - // Only load undeleted messages of the current user and group by thread. - $fragments['where'][] = 'pmi.uid = %d'; - $fragments['query_args']['where'][] = $account->uid; + // Build the query to load all messages for this user. + $query_parts = _privatemsg_build_where_clause($account); + $fragments['where'][] = $query_parts['where']; + $fragments['query_args']['where'] = array_merge($fragments['query_args']['where'], $query_parts['args']); + + // Only load undeleted messages and group by thread. $fragments['where'][] = 'pmi.deleted = 0'; $fragments['group_by'][] = 'pmi.thread_id'; @@ -792,8 +860,10 @@ function privatemsg_sql_load(&$fragments $fragments['where'][] = 'pmi.mid IN (' . db_placeholders($pmids) . ')'; $fragments['query_args']['where'] += $pmids; if ($account) { - $fragments['where'][] = 'pmi.uid = %d'; - $fragments['query_args']['where'][] = $account->uid; + // Build the query to load all messages for this user. + $query_parts = _privatemsg_build_where_clause($account); + $fragments['where'][] = $query_parts['where']; + $fragments['query_args']['where'] = array_merge($fragments['query_args']['where'], $query_parts['args']); } $fragments['order_by'][] = 'pm.timestamp ASC'; } @@ -818,9 +888,10 @@ function privatemsg_sql_messages(&$fragm $fragments['query_args']['where'] += $threads; $fragments['inner_join'][] = 'INNER JOIN {pm_message} pm ON (pm.mid = pmi.mid)'; if ($account) { - // Only load the user's messages. - $fragments['where'][] = 'pmi.uid = %d'; - $fragments['query_args']['where'][] = $account->uid; + // Build the query to load all messages for this user. + $query_parts = _privatemsg_build_where_clause($account); + $fragments['where'][] = $query_parts['where']; + $fragments['query_args']['where'] = array_merge($fragments['query_args']['where'], $query_parts['args']); } if (!$load_all) { // Also load deleted messages when requested. @@ -851,12 +922,18 @@ function privatemsg_sql_participants(&$f // Only load each participant once since they are listed as recipient for // every message of that thread. - $fragments['select'][] = 'DISTINCT(pmi.uid) AS uid'; - $fragments['select'][] = 'u.name AS name'; + $fragments['select'][] = 'pmi.recipient'; + $fragments['select'][] = 'u.name'; + $fragments['select'][] = 'pmi.type'; - $fragments['inner_join'][] = 'INNER JOIN {users} u ON (u.uid = pmi.uid)'; + + $fragments['inner_join'][] = "LEFT JOIN {users} u ON (u.uid = pmi.recipient AND pmi.type = 'user')"; $fragments['where'][] = 'pmi.thread_id = %d'; $fragments['query_args']['where'][] = $thread_id; + + $fragments['group_by'][] = 'pmi.recipient'; + $fragments['group_by'][] = 'u.name'; + $fragments['group_by'][] = 'pmi.type'; } /** @@ -870,13 +947,17 @@ function privatemsg_sql_participants(&$f function privatemsg_sql_unread_count(&$fragments, $account) { $fragments['primary_table'] = '{pm_index} pmi'; - $fragments['select'][] = 'COUNT(DISTINCT thread_id) as unread_count'; + $query_parts = _privatemsg_build_where_clause($account); + + $fragments['select'][] = "(COUNT(DISTINCT thread_id) - (SELECT COUNT(DISTINCT thread_id) FROM {pm_index} pmie WHERE (" . $query_parts['where'] . ") AND pmi.deleted = 0 AND pmi.is_new = 1 AND pmi.type <> 'user')) as unread_count"; + $fragments['query_args']['where'] = array_merge($fragments['query_args']['where'], $query_parts['args']); // Only count new messages that have not been deleted. $fragments['where'][] = 'pmi.deleted = 0'; $fragments['where'][] = 'pmi.is_new = 1'; - $fragments['where'][] = 'pmi.uid = %d'; - $fragments['query_args']['where'][] = $account->uid; + // Build the query to load all messages for this user. + $fragments['where'][] = $query_parts['where']; + $fragments['query_args']['where'] = array_merge($fragments['query_args']['where'], $query_parts['args']); } /** @@ -908,6 +989,30 @@ function privatemsg_sql_autocomplete(&$f $fragments['where'][] = 'u.status <> 0'; $fragments['order_by'][] = 'u.name ASC'; } +/** + * Query definition to search for username autocomplete suggestions. + * + * @param $fragments + * Query fragments array. + * @param $search + * Which search string is currently searched for. + * @param $names + * Array of names not to be used as suggestions. + */ +function privatemsg_sql_autocomplete_roles(&$fragments, $search, $names) { + $fragments['primary_table'] = '{role} r'; + $fragments['select'][] = 'r.name'; + + // Escape the % to get it through the placeholder replacement. + $fragments['where'][] = "r.name LIKE '%s'"; + $fragments['query_args']['where'][] = $search .'%%'; + if (!empty($names)) { + // If there are already names selected, exclude them from the suggestions. + $fragments['where'][] = "r.name NOT IN (". db_placeholders($names, 'text') .")"; + $fragments['query_args']['where'] += $names; + } + $fragments['order_by'][] = 'r.name ASC'; +} /** * Query Builder function to load all messages that should be flushed. @@ -1020,10 +1125,10 @@ function privatemsg_user($op, &$edit, &$ } // Delete recipient entries of that user. - db_query('DELETE FROM {pm_index} WHERE uid = %d', $account->uid); + db_query("DELETE FROM {pm_index} WHERE recipient = %d and type = 'user'", $account->uid); // DELETE any disable flag for user. - db_query('DELETE from {pm_disable} where uid=%d', $account->uid); + db_query("DELETE from {pm_disable} WHERE uid = %d", $account->uid); break; } } @@ -1123,7 +1228,12 @@ function privatemsg_message_change_delet } if ($account) { - db_query('UPDATE {pm_index} SET deleted = %d WHERE mid = %d AND uid = %d', $delete_value, $pmid, $account->uid); + db_query("UPDATE {pm_index} SET deleted = %d WHERE mid = %d AND recipient = %d AND type = 'user'", $delete_value, $pmid, $account->uid); + if (db_affected_rows() == 0) { + $message = privatemsg_message_load($pmid); + $index_sql = "INSERT INTO {pm_index} (mid, thread_id, recipient, type, is_new, deleted) VALUES (%d, %d, %d, '%s', %d, %d)"; + db_query($index_sql, $pmid, $message['thread_id'], $account->uid, 'user', 0, 1); + } } else { // Mark deleted for all users. @@ -1388,14 +1498,14 @@ function _privatemsg_send($message) { drupal_alter('privatemsg_message_presave', $message); - $index_sql = "INSERT INTO {pm_index} (mid, thread_id, uid, is_new, deleted) VALUES (%d, %d, %d, %d, 0)"; + $index_sql = "INSERT INTO {pm_index} (mid, thread_id, recipient, type, is_new, deleted) VALUES (%d, %d, %d, '%s', %d, 0)"; if (isset($message['read_all']) && $message['read_all']) { // The message was sent in read all mode, add the author as recipient to all // existing messages. $query_messages = _privatemsg_assemble_query('messages', array($message['thread_id']), NULL); $conversation = db_query($query_messages['query']); while ($result = db_fetch_array($conversation)) { - if (!db_query($index_sql, $result['mid'], $message['thread_id'], $message['author']->uid, 0)) { + if (!db_query($index_sql, $result['mid'], $message['thread_id'], $message['author']->uid, 'user', 0)) { return FALSE; } } @@ -1421,7 +1531,11 @@ function _privatemsg_send($message) { // 2) Save message to recipients. // Each recipient gets a record in the pm_index table. foreach ($message['recipients'] as $recipient) { - if (!db_query($index_sql, $mid, $message['thread_id'], $recipient->uid, 1) ) { + if (!isset($recipient->type)) { + $recipient->type = 'user'; + $recipient->key = 'uid'; + } + if (!db_query($index_sql, $mid, $message['thread_id'], $recipient->{$recipient->key}, $recipient->type, 1) ) { // We assume if one insert failed then the rest may fail too against the // same table. return FALSE; @@ -1433,7 +1547,7 @@ function _privatemsg_send($message) { $is_new = isset($message['recipients'][$message['author']->uid]) ? 1 : 0; // Also add a record for the author to the pm_index table. - if (!db_query($index_sql, $mid, $message['thread_id'], $message['author']->uid, $is_new)) { + if (!db_query($index_sql, $mid, $message['thread_id'], $message['author']->uid, 'user', $is_new)) { return FALSE; } @@ -1712,7 +1826,7 @@ function privatemsg_thread_change_status } // Merge status and uid with the threads list. array_merge() will not overwrite/ignore thread_id 1. $params = array_merge(array($status, $account->uid), $threads); - db_query('UPDATE {pm_index} SET is_new = %d WHERE uid = %d AND thread_id IN ('. db_placeholders($threads) .')', $params); + db_query("UPDATE {pm_index} SET is_new = %d WHERE recipient = %d and type = 'user' AND thread_id IN (" . db_placeholders($threads) . ')', $params); if ($status == PRIVATEMSG_UNREAD) { drupal_set_message(format_plural(count($threads), 'Marked 1 thread as unread.', 'Marked @count threads as unread.')); @@ -1815,15 +1929,23 @@ function privatemsg_thread_change_delete function privatemsg_privatemsg_block_message($author, $recipients) { $blocked = array(); if (privatemsg_is_disabled($author)) { - $blocked[] = array('uid' => $author->uid, - 'message' => t('You have disabled private message sending and receiving.'), - ); + $blocked[] = array( + 'uid' => $author->uid, + 'message' => t('You have disabled private message sending and receiving.'), + ); } foreach($recipients as $recipient) { if (privatemsg_is_disabled($recipient)) { - $blocked[] = array('uid' => $recipient->uid, - 'message' => t('%recipient has disabled private message receiving.', array('%recipient' => $recipient->name)) - ); + $blocked[] = array( + 'uid' => $recipient->uid, + 'message' => t('%recipient has disabled private message receiving.', array('%recipient' => $recipient->name)), + ); + } + if (isset($recipient->type) && $recipient->type == 'role' && !privatemsg_user_access('write privatemg to roles')) { + $blocked[] = array( + 'uid' => $recipient->recipient, + 'message' => t('Not allowed to write private messages to role members'), + ); } } @@ -1921,4 +2043,63 @@ function privatemsg_views_api() { 'api' => 2, 'path' => drupal_get_path('module', 'privatemsg') . '/views', ); +} + +/** + * Implements hook_privatemsg_recipient_autocomplete(). + */ +function privatemsg_privatemsg_recipient_autocomplete($fragment, $names, $limit) { + $query = _privatemsg_assemble_query('autocomplete_roles', $fragment, $names); + $result = db_query_range($query['query'], $fragment, 0, $limit); + $prefix = count($names) ? implode(", ", $names) .", " : ''; + // 3: Build proper suggestions and print. + $matches = array(); + while ($role = db_fetch_object($result)) { + $matches[$prefix . $role->name .", "] = t('Role %role', array('%role' => $role->name)); + } + return $matches; +} + +/** + * Implements hook_privatemsg_name_lookup(). + */ +function privatemsg_privatemsg_name_lookup($string) { + $result = db_query("SELECT * FROM {role} WHERE name = '%s'", $string); + if ($role = db_fetch_object($result)) { + $role->type = 'role'; + $role->key = 'rid'; + return $role; + } +} + +/** + * Implements hook_privatemsg_recipients_where(). + */ +function privatemsg_privatemsg_recipients_where($account) { + return array( + 'where' => array("pmi.type = 'role' AND pmi.recipient IN (" . db_placeholders(array_keys($account->roles)) . ")"), + 'args' => array_keys($account->roles), + ); +} + +/** + * Implements hook_privatemgs_sql_participants_alter(). + */ +function privatemsg_privatemsg_sql_participants_alter(&$fragments, $thread_id) { + $fragments['select'][] = 'r.name AS role_name'; + $fragments['select'][] = "'rid' AS role_key"; + + $fragments['inner_join'][] = "LEFT JOIN {role} r ON (r.rid = pmi.recipient AND pmi.type = 'role')"; + $fragments['group_by'][] = 'role_name'; +} + +/** + * Implements hook_privatemsg_is_recipient(). + */ +function privatemsg_privatemsg_is_recipient($account, $participants) { + foreach ($account->roles as $role_id => $role_name) { + if (isset($participants['role_' . $role_id])) { + return TRUE; + } + } } \ No newline at end of file Index: privatemsg.pages.inc =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.pages.inc,v retrieving revision 1.1 diff -u -p -r1.1 privatemsg.pages.inc --- privatemsg.pages.inc 2 Dec 2009 20:03:59 -0000 1.1 +++ privatemsg.pages.inc 15 Jan 2010 13:38:47 -0000 @@ -200,15 +200,15 @@ function privatemsg_new(&$form_state, $r continue; } // Check if another module is blocking the sending of messages to the recipient by current user. - $user_blocked = module_invoke_all('privatemsg_block_message', $user, array($recipient->uid => $recipient)); - if (!count($user_blocked) <> 0 && $recipient->uid) { - if ($recipient->uid == $user->uid) { + $user_blocked = module_invoke_all('privatemsg_block_message', $user, array($recipient->recipient => $recipient)); + if (!count($user_blocked) <> 0 && $recipient->recipient) { + if ($recipient->recipient == $user->uid) { $usercount++; // Skip putting author in the recipients list for now. continue; } $to[] = $recipient->name; - $to_themed[$recipient->uid] = theme('username', $recipient); + $to_themed[$recipient->type . '_' . $recipient->recipient] = _privatemsg_format_participant($recipient); } else { // Recipient list contains blocked users. @@ -219,7 +219,7 @@ function privatemsg_new(&$form_state, $r if (empty($to) && $usercount >= 1 && !$blocked) { // Assume the user sent message to own account as if the usercount is one or less, then the user sent a message but not to self. $to[] = $user->name; - $to_themed[$user->uid] = theme('username', $user); + $to_themed[$user->uid] = _privatemsg_format_participant($user); } if (!empty($to)) { @@ -363,8 +363,8 @@ function privatemsg_new_validate($form, // Load participants. $message['recipients'] = _privatemsg_load_thread_participants($message['thread_id']); // Remove author. - if (isset($message['recipients'][$message['author']->uid]) && count($message['recipients']) > 1) { - unset($message['recipients'][$message['author']->uid]); + if (isset($message['recipients']['user_' . $message['author']->uid]) && count($message['recipients']) > 1) { + unset($message['recipients']['user_' . $message['author']->uid]); } } @@ -387,7 +387,12 @@ function privatemsg_new_submit($form, &$ // Load usernames to which the message was sent to. $recipient_names = array(); foreach ($form_state['validate_built_message']['recipients'] as $recipient) { - $recipient_names[] = theme('username', $recipient); + if (isset($recipient->uid)) { + $recipient_names[] = _privatemsg_format_participant($recipient); + } + else { + $recipient_names[] = $recipient->name; + } } if ($status !== FALSE ) { drupal_set_message(t('A message has been sent to !recipients.', array('!recipients' => implode(', ', $recipient_names)))); @@ -641,17 +646,26 @@ function privatemsg_user_name_autocomple $names[$name] = $name; } } - // By using user_validate_user we can ensure that names included in $names are at least logisticaly possible. // 2: Find the next user name suggestion. $fragment = array_pop($names); $matches = array(); if (!empty($fragment)) { - $query = _privatemsg_assemble_query('autocomplete', $fragment, $names); - $result = db_query_range($query['query'], $fragment, 0, 10); - $prefix = count($names) ? implode(", ", $names) .", " : ''; - // 3: Build proper suggestions and print. - while ($user = db_fetch_object($result)) { - $matches[$prefix . $user->name .", "] = $user->name; + $remaining = 10; + foreach (module_implements('privatemsg_recipient_autocomplete') as $module) { + $matches += module_invoke($module, 'privatemsg_recipient_autocomplete', $fragment, $names, $remaining); + $remaining = 10 - count($matches); + if ($remaining <= 0) { + break; + } + } + if ($remaining > 0) { + $query = _privatemsg_assemble_query('autocomplete', $fragment, $names); + $result = db_query_range($query['query'], $fragment, 0, $remaining); + $prefix = count($names) ? implode(", ", $names) .", " : ''; + // 3: Build proper suggestions and print. + while ($user = db_fetch_object($result)) { + $matches[$prefix . $user->name .", "] = $user->name; + } } } // convert to object to prevent drupal bug, see http://drupal.org/node/175361 Index: privatemsg.test =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg.test,v retrieving revision 1.6 diff -u -p -r1.6 privatemsg.test --- privatemsg.test 2 Jan 2010 12:11:09 -0000 1.6 +++ privatemsg.test 15 Jan 2010 13:38:47 -0000 @@ -304,7 +304,7 @@ class PrivatemsgTestCase extends DrupalW ); $this->drupalPost(NULL, $reply, t('Send message')); - $this->assertText(t('A message has been sent to @recipient, @author.', array('@recipient' => $recipient->name, '@author' => $author->name)), 'Reply has been sent.'); + $this->assertText(t('A message has been sent to @author, @recipient.', array('@recipient' => $recipient->name, '@author' => $author->name)), 'Reply has been sent.'); $this->assertText($reply['body'], 'New message body displayed.'); $this->drupalPost(NULL, $replyempty, t('Send message')); @@ -450,7 +450,7 @@ class PrivatemsgTestCase extends DrupalW $this->assertText($edit['body'], t('First message body displayed.')); $this->assertText($admin_edit['body'], t('New message body displayed.')); - $admin_recipient_count = db_result(db_query("SELECT COUNT(*) FROM {pm_index} WHERE uid = %d AND thread_id = %d", $admin->uid, 1)); + $admin_recipient_count = db_result(db_query("SELECT COUNT(*) FROM {pm_index} WHERE recipient = %d AND thread_id = %d", $admin->uid, 1)); $this->assertEqual($admin_recipient_count, 2, t('Admin is listed as recipient for every message once.')); @@ -465,7 +465,7 @@ class PrivatemsgTestCase extends DrupalW $this->assertText($admin_edit['body'], t('Second response body displayed.')); $this->assertText($admin_edit2['body'], t('Third message body displayed.')); - $admin_recipient_count = db_result(db_query("SELECT COUNT(*) FROM {pm_index} WHERE uid = %d AND thread_id = %d", $admin->uid, 1)); + $admin_recipient_count = db_result(db_query("SELECT COUNT(*) FROM {pm_index} WHERE recipient = %d AND thread_id = %d", $admin->uid, 1)); $this->assertEqual($admin_recipient_count, 3, t('Admin is listed as recipient for every message once.')); } Index: pm_block_user/pm_block_user.module =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/pm_block_user/pm_block_user.module,v retrieving revision 1.3 diff -u -p -r1.3 pm_block_user.module --- pm_block_user/pm_block_user.module 2 Dec 2009 20:04:00 -0000 1.3 +++ pm_block_user/pm_block_user.module 15 Jan 2010 13:38:48 -0000 @@ -181,7 +181,7 @@ function pm_block_user_privatemsg_block_ function pm_block_user_privatemsg_sql_load_alter(&$fragments, $pmid, $uid) { $fragments['select'][] = 'pmbu.recipient AS is_blocked'; - $fragments['inner_join'][] = 'LEFT JOIN {pm_block_user} pmbu ON (pm.author = pmbu.author AND pmi.uid = pmbu.recipient)'; + $fragments['inner_join'][] = "LEFT JOIN {pm_block_user} pmbu ON (pm.author = pmbu.author AND pmi.recipient = pmbu.recipient AND pmi.type = 'user')"; } /** Index: pm_email_notify/pm_email_notify.module =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/pm_email_notify/pm_email_notify.module,v retrieving revision 1.3 diff -u -p -r1.3 pm_email_notify.module --- pm_email_notify/pm_email_notify.module 2 Dec 2009 20:04:00 -0000 1.3 +++ pm_email_notify/pm_email_notify.module 15 Jan 2010 13:38:48 -0000 @@ -52,7 +52,7 @@ function _pm_email_notify_is_enabled($ui function pm_email_notify_privatemsg_message_insert($message) { foreach ($message['recipients'] as $recipient) { // check if recipient enabled email notifications - if (_pm_email_notify_is_enabled($recipient->uid)) { + if (isset($recipient->uid) && _pm_email_notify_is_enabled($recipient->uid)) { // send them a new pm notification email if they did $params['recipient'] = $recipient; $params['message'] = $message; Index: privatemsg_filter/privatemsg_filter.module =================================================================== RCS file: /cvs/drupal/contributions/modules/privatemsg/privatemsg_filter/privatemsg_filter.module,v retrieving revision 1.3 diff -u -p -r1.3 privatemsg_filter.module --- privatemsg_filter/privatemsg_filter.module 2 Dec 2009 20:04:00 -0000 1.3 +++ privatemsg_filter/privatemsg_filter.module 15 Jan 2010 13:38:48 -0000 @@ -589,7 +589,7 @@ function privatemsg_filter_privatemsg_sq $count = 0; if (isset($filter['tags']) && !empty($filter['tags'])) { foreach ($filter['tags'] as $tag) { - $fragments['inner_join'][] = "INNER JOIN {pm_tags_index} pmti$count ON (pmti$count.thread_id = pmi.thread_id AND pmti$count.uid = pmi.uid)"; + $fragments['inner_join'][] = "INNER JOIN {pm_tags_index} pmti$count ON (pmti$count.thread_id = pmi.thread_id AND pmti$count.uid = pmi.recipient AND pmi.type = 'user')"; $fragments['where'][] = "pmti$count.tag_id = %d"; $fragments['query_args']['where'][] = $tag; $count++; @@ -599,7 +599,7 @@ function privatemsg_filter_privatemsg_sq if (isset($filter['author']) && !empty($filter['author'])) { foreach ($filter['author'] as $author) { $fragments['inner_join'][] = "INNER JOIN {pm_index} pmi$count ON (pmi$count.mid = pm.mid)"; - $fragments['where'][] = "pmi$count.uid = %d"; + $fragments['where'][] = "pmi$count.recipient = %d AND type = 'user'"; $fragments['query_args']['where'][] = $author->uid; $count++; } @@ -752,10 +752,10 @@ function privatemsg_filter_privatemsg_sq // @todo: Check if these results can be grouped to avoid unecessary loops. if (arg(1) == 'filter') { // JOIN on index entries where the to be selected user is a recipient. - $fragments['inner_join'][] = 'INNER JOIN {pm_index} pip ON pip.uid = u.uid'; + $fragments['inner_join'][] = "INNER JOIN {pm_index} pip ON pip.recipient = u.uid AND pip.type = 'user'"; // JOIN on rows where the current user is the recipient and that have the // same mid as those above. - $fragments['inner_join'][] = 'INNER JOIN {pm_index} piu ON piu.uid = %d AND pip.mid = piu.mid'; + $fragments['inner_join'][] = "INNER JOIN {pm_index} piu ON piu.recipient = u.uid AND piu.type = 'user' AND pip.mid = piu.mid"; $fragments['query_args']['join'][] = $user->uid; } }