.../user_relationship_privatemsg.info | 10 + .../user_relationship_privatemsg.install | 51 ++++++ .../user_relationship_privatemsg.module | 180 +++++++++++++++++++ .../user_relationship_privatemsg.test | 185 ++++++++++++++++++++ 4 files changed, 426 insertions(+), 0 deletions(-) diff --git user_relationship_privatemsg/user_relationship_privatemsg.info user_relationship_privatemsg/user_relationship_privatemsg.info new file mode 100755 index 0000000..a4ca05b --- /dev/null +++ user_relationship_privatemsg/user_relationship_privatemsg.info @@ -0,0 +1,10 @@ +; $Id$ +name = Privatemsg integration +description = Allows to send message to relationships. +package = "User Relationships" +core = 6.x +dependencies[] = privatemsg +dependencies[] = user_relationships_api +dependencies[] = user_relationships_ui + + diff --git user_relationship_privatemsg/user_relationship_privatemsg.install user_relationship_privatemsg/user_relationship_privatemsg.install new file mode 100644 index 0000000..74b5132 --- /dev/null +++ user_relationship_privatemsg/user_relationship_privatemsg.install @@ -0,0 +1,51 @@ + array( + 'urpid' => array( + 'type' => 'serial', + 'not NULL' => TRUE, + ), + 'rtid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'author' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + ), + 'primary key' => array('urpid'), + 'unique keys' => array( + 'rtid_author' => array('rtid', 'author'), + ), + ); + + return $schema; +} + +/** + * Implements hook_install(). + */ +function user_relationship_privatemsg_install() { + drupal_install_schema('user_relationship_privatemsg'); +} + +/** + * Implements hook_uninstall(). + */ +function user_relationship_privatemsg_uninstall() { + drupal_uninstall_schema('user_relationship_privatemsg'); +} diff --git user_relationship_privatemsg/user_relationship_privatemsg.module user_relationship_privatemsg/user_relationship_privatemsg.module new file mode 100644 index 0000000..e3d92d8 --- /dev/null +++ user_relationship_privatemsg/user_relationship_privatemsg.module @@ -0,0 +1,180 @@ + array( + 'arguments' => array('relationship' => NULL, 'options' => array()), + ), + ); +} + +/** + * Implements hook_privatemsg_recipient_types_info(). + */ +function user_relationship_privatemsg_privatemsg_recipient_type_info() { + $types = user_relationships_types_load(); + + // If there is no relationship defined, don't expose it as a recipient type. + if (empty($types)) { + return; + } + + return array( + 'user_relationship' => array( + 'name' => t('User relationship'), + 'description' => t('Enter the name of a user relationship to write a message to all related users. Example: %example.', array('%example' => reset($types)->plural_name)), + 'format' => 'user_relationship_privatemsg_format', + 'load' => 'user_relationship_privatemsg_load_multiple', + 'autocomplete' => 'user_relationship_privatemsg_autocomplete', + 'generate recipients' => 'user_relationship_privatemsg_load_recipients', + 'count' => 'user_relationship_privatemsg_count_recipients', + 'write callback' => 'user_relationship_privatemsg_check_write_access', + 'view access' => 'view relationship recipients', + ), + ); +} + +function user_relationship_privatemsg_check_write_access($relationship = NULL) { + global $user; + // Users are only allowed to write their own related users. + if ($relationship) { + if (!isset($relationship->account)) { + $author = db_result(db_query('SELECT author FROM {user_relationship_privatemsg} WHERE urpid = %d', $relationship->recipient)); + $relationship->account = privatemsg_user_load($author); + } + if ($relationship->account->uid != $user->uid) { + return FALSE; + } + } + return user_access('write privatemsg to relationships'); +} + +/** + * Format a relationship for displaying as recipient. + */ +function theme_user_relationship_privatemsg_format($relationship) { + global $user; + if ($relationship->account->uid == $user->uid) { + return t('Your %relationship (relationship)', array('%relationship' => $relationship->plural_name)); + } + return t('%relationship of !username (relationship)', array('%relationship' => $relationship->plural_name, '!username' => theme('username', $relationship->account))); +} + +/** + * Load relationships based on their rtid. + */ +function user_relationship_privatemsg_load_multiple($urpids) { + global $user; + $relationships = array(); + $result = db_query('SELECT * FROM {user_relationship_privatemsg} WHERE urpid IN (' . db_placeholders($urpids) . ')', $urpids); + while ($row = db_fetch_object($result)) { + if ($relationship = user_relationships_type_load($row->rtid)) { + $relationship->type = 'user_relationship'; + $relationship->recipient = $row->urpid; + $relationship->account = privatemsg_user_load($row->author); + $relationships[privatemsg_recipient_key($relationship)] = $relationship; + } + } + return $relationships; +} + +/** + * Returns the recipient id for a rtid - author combination. + */ +function _user_relationship_privatemsg_get_recipient_id($rtid, $uid) { + if ($urpid = db_result(db_query('SELECT urpid FROM {user_relationship_privatemsg} WHERE rtid = %d AND author = %d', $rtid, $uid))) { + return $urpid; + } + db_query('INSERT INTO {user_relationship_privatemsg} (rtid, author) VALUES (%d, %d)', $rtid, $uid); + return db_last_insert_id('user_relationship_privatemsg', 'urpid'); +} + +/** + * Load a number of recipient user ids. + */ +function user_relationship_privatemsg_load_recipients($relationship, $limit, $offset) { + $recipients = array(); + $relationships = user_relationships_load(array('user' => $relationship->account->uid, 'rtid' => $relationship->rtid), array('limit' => $offset > 0 ? "$limit OFFSET $offset" : $limit)); + foreach ($relationships as $row) { + if ($row->requester_id == $relationship->account->uid) { + $recipients[] = $row->requestee_id; + } + else { + $recipients[] = $row->requester_id; + } + } + return $recipients; +} + +/** + * Return the number of users to which the author is related. + */ +function user_relationship_privatemsg_count_recipients($relationship) { + $count_query = 'SELECT I AS count FROM {user_relationships} ur INNER JOIN {user_relationship_types} urt USING ( rtid ) WHERE (ur.requester_id = %d OR ((ur.approved <> 1 OR urt.is_oneway <> 0) AND ur.requestee_id = %d)) AND %s.%s = %d'; + return user_relationships_load(array('user' => $relationship->account->uid, 'rtid' => $relationship->rtid), array('count' => TRUE)); +} + +/** + * Return relationship autocomplete suggestions. + */ +function user_relationship_privatemsg_autocomplete($fragment, $names, $limit) { + $query = _privatemsg_assemble_query(array('autocomplete_roles', 'user_relationship_privatemsg'), $fragment, $names); + $result = db_query_range($query['query'], $fragment, 0, $limit); + $matches = array(); + while ($role = db_fetch_object($result)) { + $matches[$role->plural_name] = $role->plural_name; + } + return $matches; +} + +/** + * Implements hook_privatemsg_name_lookup(). + */ +function user_relationship_privatemsg_privatemsg_name_lookup($string) { + global $user; + $relationship = str_replace(t('[user_relationship]'), '', $string); + if ($recipient = user_relationships_type_load(array('plural_name' => $relationship))) { + $recipient->type = 'user_relationship'; + $recipient->recipient = _user_relationship_privatemsg_get_recipient_id($recipient->rtid, $user->uid); + $recipient->account = $user; + return $recipient; + } +} + +/** + * 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 user_relationship_privatemsg_sql_autocomplete_roles(&$fragments, $search, $names) { + $fragments['primary_table'] = '{user_relationship_types} urt'; + $fragments['select'][] = 'urt.plural_name'; + + // Escape the % to get it through the placeholder replacement. + $fragments['where'][] = "urt.plural_name LIKE '%s'"; + $fragments['query_args']['where'][] = $search .'%%'; + if (!empty($names)) { + // If there are already names selected, exclude them from the suggestions. + $fragments['where'][] = "urt.plural_name NOT IN (". db_placeholders($names, 'text') .")"; + $fragments['query_args']['where'] += $names; + } + $fragments['order_by'][] = 'urt.plural_name ASC'; +} diff --git user_relationship_privatemsg/user_relationship_privatemsg.test user_relationship_privatemsg/user_relationship_privatemsg.test new file mode 100644 index 0000000..6c1f0ed --- /dev/null +++ user_relationship_privatemsg/user_relationship_privatemsg.test @@ -0,0 +1,185 @@ + t('User Relationships Privatemsg recipients'), + 'description' => t('Check relationship recipient type for privatemsg'), + 'group' => t('User Relationships'), + 'dependencies' => array('privatemsg'), + ); + } + + /** + * Enable required modules. + */ + function setUp() { + return parent::setUp('privatemsg', 'user_relationships_api', 'user_relationships_ui', 'user_relationship_privatemsg'); + } + + /** + * Tests sending a message to related users. + */ + function testSendtoRelationship() { + $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'can have relationships', 'view relationship recipients', 'administer user relationships', 'maintain own relationships', 'write privatemsg to relationships', 'access user profiles')); + $userA = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'can have relationships', 'view relationship recipients', 'write privatemsg to relationships')); + $userB = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'can have relationships', 'view relationship recipients')); + + $this->drupalLogin($admin); + + // Create relationship. + $relationship = array( + 'name' => $this->randomName(), + 'plural_name' => $this->randomName(), + 'requires_approval' => FALSE, + ); + $this->drupalPost('admin/user/relationships/add', $relationship, t('Submit')); + + // Become related to user A and B. + $this->drupalGet('relationship/' . $userA->uid . '/request/1'); + $this->drupalPost(NULL, array(), t('Send')); + $this->drupalGet('relationship/' . $userB->uid . '/request/1'); + $this->drupalPost(NULL, array(), t('Send')); + + // Send a message to related users. + $this->drupalGet('messages/new'); + $this->assertText(t('Enter the name of a user relationship to write a message to all related users. Example: @relationship.', array('@relationship' => $relationship['plural_name'])), t('Description is displayed.')); + + $message = array( + 'recipient' => $relationship['plural_name'], + 'subject' => $this->randomName(), + 'body' => $this->randomName(50), + ); + $this->drupalPost(NULL, $message, t('Send message')); + $this->assertText(t('A message has been sent to Your @relationship (relationship).', array('@relationship' => $relationship['plural_name']))); + + // Check if userA recieved the message and is able to respond. + $this->drupalLogin($userA); + $this->drupalGet('messages'); + $this->clickLink($message['subject']); + $this->assertText($message['body']); + + // Check recipients. + $this->assertText(t('Recipients: @admin', array('@admin' => $admin->name))); + + // Send a reply + $reply = array('body' => $this->randomName(50)); + $this->drupalPost(NULL, $reply, t('Send message')); + + // Login as userB and make sure the original message is displayed but not the message nor the username of userA. + $this->drupalLogin($userB); + $this->drupalGet('messages'); + $this->clickLink($message['subject']); + $this->assertText($message['body']); + $this->assertNoText($userA->name); + + // Check recipients. + $this->assertText(t('Recipients: @admin', array('@admin' => $admin->name))); + + // Log in as admin and check that the response of user A is visible. + $this->drupalLogin($admin); + $this->drupalGet('messages'); + $this->clickLink($message['subject']); + $this->assertText($reply['body']); + + // Check recipients. + $this->assertText(t('Recipients: @userA, Your @relationship (relationship)', array('@userA' => $userA->name, '@relationship' => $relationship['plural_name']))); + + $reply2 = array('body' => $this->randomName(50)); + $this->drupalPost(NULL, $reply2, t('Send message')); + + // Log in as user B again and check that the reply but not user a is visible. + $this->drupalLogin($userB); + $this->drupalGet('messages'); + $this->clickLink($message['subject']); + $this->assertText($reply2['body']); + // @todo: does not yet work. + //$this->assertNoText($userA->name); + + // Test reverse relationship. + $this->drupalLogin($userA); + $this->drupalGet('messages/new'); + $this->assertText(t('Enter the name of a user relationship to write a message to all related users. Example: @relationship.', array('@relationship' => $relationship['plural_name'])), t('Description is displayed.')); + + $message = array( + 'recipient' => $relationship['plural_name'], + 'subject' => $this->randomName(), + 'body' => $this->randomName(50), + ); + $this->drupalPost(NULL, $message, t('Send message')); + $this->assertText(t('A message has been sent to Your @relationship (relationship).', array('@relationship' => $relationship['plural_name']))); + + // Log in as admin and check that the response of user A is visible. + $this->drupalLogin($admin); + $this->drupalGet('messages'); + $this->clickLink($message['subject']); + $this->assertText($message['body']); + + // Check recipients. + $this->assertText(t('Recipients: @userA', array('@userA' => $userA->name))); + } + + /** + * Test a relationship with bath api processing. + */ + function testManyRelations() { + $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'can have relationships', 'view relationship recipients', 'administer user relationships', 'maintain own relationships', 'write privatemsg to relationships', 'access user profiles')); + + $this->drupalLogin($admin); + + // Create relationship. + $relationship = array( + 'name' => $this->randomName(), + 'plural_name' => $this->randomName(), + 'requires_approval' => FALSE, + ); + $this->drupalPost('admin/user/relationships/add', $relationship, t('Submit')); + + // Create 25 users (more than are allowed to be process directly) and relate + // them to the admin. + $users = array(); + for ($i = 0; $i < 25; $i++) { + $users[$i] = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'can have relationships', 'view relationship recipients', 'write privatemsg to relationships')); + // Become related to that user. + $this->drupalGet('relationship/' . $users[$i]->uid . '/request/1'); + $this->drupalPost(NULL, array(), t('Send')); + } + variable_set('privatemsg_recipient_small_threshold', 20); + + // Send a message to related users. + $this->drupalGet('messages/new'); + $this->assertText(t('Enter the name of a user relationship to write a message to all related users. Example: @relationship.', array('@relationship' => $relationship['plural_name'])), t('Description is displayed.')); + + $message = array( + 'recipient' => $relationship['plural_name'], + 'subject' => $this->randomName(), + 'body' => $this->randomName(50), + ); + $this->drupalPost(NULL, $message, t('Send message')); + $this->assertText(t('A message has been sent to Your @relationship (relationship).', array('@relationship' => $relationship['plural_name']))); + + // Test if all recipients see the message. + foreach ($users as $user) { + $this->drupalLogin($user); + $this->drupalGet('messages'); + $this->clickLink($message['subject']); + $this->assertText($message['body']); + + // Check recipients. + $this->assertText(t('Recipients: @admin', array('@admin' => $admin->name))); + } + } +}