Index: pm_service/pm_service.inc =================================================================== RCS file: pm_service/pm_service.inc diff -N pm_service/pm_service.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ pm_service/pm_service.inc 3 Jan 2011 21:06:49 -0000 @@ -0,0 +1,285 @@ + 0) && ($uid != $user->uid)) { + if (user_access("read all private messages")) { + $account = user_load($uid); + } + else { + return services_error(t('This user does not have permissions to read all messages.'), 403); + } + } + // Use the current user for the account. + else { + $account = $user; + } + + // Construct the query and retrieve the correct set of messages. + $query = _privatemsg_assemble_query('list', $account, $type); + + // Handle any paging if an offset or a limit was passed in. + if (empty($offset) && !empty($limit)) { + $result = db_query_range($query['query'], 0, $limit); + } + elseif (!empty($offset) && !empty($limit)) { + $result = db_query_range($query['query'], $offset, $limit); + } + elseif (!empty($offset) && empty($limit)) { + $rows = (int)db_result(db_query($query['count'])); + $result = db_query_range($query['query'], $offset, $rows); + } + else { + // No paging, we are retrieving everything. + $result = db_query($query['query']); + } + + // Loop the result object to get the messages. + while ($row = db_fetch_object($result)) { + // If the full thread should be loaded, created an array + // using the thread_id as the index. + if ($load_full) { + $pms[$row->thread_id] = $row; + } + // For message previews, just create a numbered array. + else { + $pms[] = $row; + } + } + + // Load the full thread, if necessary. + if (!empty($pms) && $load_full) { + foreach ($pms as $thread_id => $msg) { + $messages[] = privatemsg_thread_load($thread_id, $account, NULL, FALSE); + } + } + // Otherwise, just return message previews. + else { + $messages = $pms; + } + + // Return messages. + return $messages; + +} + +/** + * Get the number of unread private messages of the logged-in user. + * + * @return + * The unread count. + */ +function pm_service_unread_count($uid = '') { + + // User needs to be authenticated to proceed. + global $user; + if (!user_is_logged_in()) { + return services_error(t('This user is not logged in.'), 403); + } + + // If a user id other than the current user's ID is passed, + // validate that the authenticated user has the correct + // permissions to read another user's messages. + if (is_numeric($uid) && ($uid != $user->uid)) { + if (user_access("read all private messages")) { + $account = user_load($uid); + } + else { + return services_error(t('This user does not have permissions to use this service.'), 403); + } + } + // Use the current user for the account. + else { + $account = $user; + } + + // Return unread count. + return privatemsg_unread_count($account); + +} + +/** + * Send a private message to one or more recipients. + * + * @param $recipients + * String. A comma separated list of usernames for recipients of the message. + * + * @param $subject + * String. A message subject + * + * @param $body + * String. A message body + * + * @return + * Boolean. Return TRUE if sending the message was successful. + */ +function pm_service_send($recipients = '', $subject = '', $body = '') { + + $form_state = array(); + + // Make sure the message author is logged in. + if (!user_is_logged_in()) { + return services_error(t('Author is not logged in.'), 403); + } + + // Validate at least 1 recipient has been passed in. + if ($recipients == '') { + return services_error(t('There are no recipients, please enter a recipient for the message.'), 400); + } + + // Validate that this messages has a subject. + if ($subject == '') { + return services_error(t('Please specify a subject line.'), 400); + } + + // Load the full user object. + global $user; + $account = user_load($user->uid); + + // Convert the recipients string to an array of user objects. + list($recipients, $invalid) = _privatemsg_parse_userstring($recipients); + + // Problem: At least one of the recipients could not be found. + if (!empty($invalid)) { + $invalid_usernames = array('@names' => implode(', ', $invalid)); + return services_error(t('One or more usernames are invalid: @names', $invalid_usernames), 400); + } + + // Attempt to send a new message. + $result = privatemsg_new_thread($recipients, $subject, $body, array('author' => $account)); + + // Return success status. + if ($result['success']) { + return TRUE; + } + else { + return services_error(implode("\n", $result['messages']['error']), 400); + } + +} + +/** + * Reply to an existing thread. + * + * @param $body + * String. A message body + * + * @param $thread_id + * Integer. A thread ID. + * + * @return + * Boolean. Return TRUE if replying to a thread was successful. + */ +function pm_service_reply($body = '', $thread_id = '') { + + $form_state = array(); + + // Make sure the message author is logged in. + if (!user_is_logged_in()) { + return services_error(t('Author is not logged in.'), 403); + } + + // Validate at least 1 recipient has been passed in. + if ($body == '') { + return services_error(t('Please specify a body for this reply.'), 400); + } + + // Validate that this messages has a subject. + if ($thread_id == '') { + return services_error(t('Please specify a thread ID for this reply.'), 400); + } + + // Load the full user object. + global $user; + $account = user_load($user->uid); + + // Attempt to send a reply. + $result = privatemsg_reply($thread_id, $body, array('author' => $account)); + + // Return success status. + if ($result['success']) { + return TRUE; + } + // If $result[0] this means the thread could not be loaded. + elseif (!empty($result[0])) { + return services_error($result[0], 404); + } + // Else there was some other problem. + else { + return services_error(implode("\n", $result['messages']['error']), 400); + } + +} + + +/** + * Get all messages in a thread. + * + * @param @thread_id + * ID of the thread to be loaded. + * @param $offset + * Optional: Message offset from the start of the thread. + * @return + * An array of messages in a thread. + */ +function pm_service_get_thread($thread_id, $offset = 0) { + + // Return if wrong paramters are passed. + if (!$thread_id || !is_numeric($thread_id)) { + return services_error(t('Invalid parameters passed'), 400); + } + + // Make sure the user is logged in. + global $user; + $account = user_load($user->uid); + if (!user_is_logged_in()) { + return services_error(t('The user is not logged in.'), 403); + } + + // Return the full thread. + return privatemsg_thread_load($thread_id, $account, $offset); + +} Index: pm_service/pm_service.info =================================================================== RCS file: pm_service/pm_service.info diff -N pm_service/pm_service.info --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ pm_service/pm_service.info 3 Jan 2011 21:06:49 -0000 @@ -0,0 +1,7 @@ +; $Id$ +name = Privatemsg Service +description = Integrates Private messages functionality with Services. +package = Services - services +dependencies[] = services +dependencies[] = privatemsg +core = 6.x Index: pm_service/pm_service.module =================================================================== RCS file: pm_service/pm_service.module diff -N pm_service/pm_service.module --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ pm_service/pm_service.module 3 Jan 2011 21:06:49 -0000 @@ -0,0 +1,161 @@ + 'pm.get', + '#callback' => 'pm_service_get', + '#access arguments' => array('get private messages from remote'), + '#file' => array('file' => 'inc', 'module' => 'pm_service'), + '#args' => array( + array( + '#name' => 'type', + '#type' => 'string', + '#optional' => TRUE, + '#description' => t('The type of messages to retrieve. Can be inbox or sent.') + ), + array( + '#name' => 'load_full', + '#type' => 'boolean', + '#optional' => TRUE, + '#description' => t('A boolean to indicate whether to load the all messages in a thread or just the message preview. Do not pass FALSE, just leave it empty for message previews.') + ), + array( + '#name' => 'offset', + '#type' => 'int', + '#optional' => TRUE, + '#description' => t('An offset integer for paging.') + ), + array( + '#name' => 'limit', + '#type' => 'int', + '#optional' => TRUE, + '#description' => t('A limit integer for paging.') + ), + array( + '#name' => 'uid', + '#type' => 'int', + '#optional' => TRUE, + '#description' => t('Instead of receiving messages from the authenticated user, receive messages from another user. The currently authenticated user needs to have the "read all private messages" permission to get messages from another user.') + ), + ), + '#return' => 'array', + '#help' => t('Get a logged-in user\'s private messages.') + ), + + // pm.getUnreadCount + array( + '#method' => 'pm.unreadCount', + '#callback' => 'pm_service_unread_count', + '#access arguments' => array('get private messages from remote'), + '#file' => array('file' => 'inc', 'module' => 'pm_service'), + '#args' => array( + array( + '#name' => 'uid', + '#type' => 'int', + '#optional' => TRUE, + '#description' => t('Instead of receiving the count of unread messages from the authenticated user, receive the count of unread messages from another user. The currently authenticated user needs to have the "read all private messages" permission to get messages from another user.') + ), + ), + '#return' => 'int', + '#help' => t('Get a users private messages unread count.') + ), + + // pm.send + array( + '#method' => 'pm.send', + '#callback' => 'pm_service_send', + '#access arguments' => array('send private messages from remote'), + '#file' => array('file' => 'inc', 'module' => 'pm_service'), + '#args' => array( + array( + '#name' => 'recipients', + '#type' => 'string', + '#description' => t('A comma separated list of recipients usernames.'), + ), + array( + '#name' => 'subject', + '#type' => 'string', + '#description' => t('A message subject.'), + ), + array( + '#name' => 'body', + '#type' => 'string', + '#optional' => TRUE, + '#description' => t('A message body.'), + ), + ), + '#return' => 'bool', + '#help' => t('Returns TRUE if the message sending was a success.') + ), + + // pm.reply + array( + '#method' => 'pm.reply', + '#callback' => 'pm_service_reply', + '#access arguments' => array('send private messages from remote'), + '#file' => array('file' => 'inc', 'module' => 'pm_service'), + '#args' => array( + array( + '#name' => 'body', + '#type' => 'string', + '#optional' => TRUE, + '#description' => t('A message body.'), + ), + array( + '#name' => 'thread_id', + '#type' => 'int', + '#optional' => TRUE, + '#description' => t('A thread ID for an existing message.'), + ), + ), + '#return' => 'bool', + '#help' => t('Returns TRUE if the message reply was a success.') + ), + + // pm.getThread + array( + '#method' => 'pm.getThread', + '#callback' => 'pm_service_get_thread', + '#access arguments' => array('get private messages from remote'), + '#file' => array('file' => 'inc', 'module' => 'pm_service'), + '#args' => array( + array( + '#name' => 'thread_id', + '#type' => 'int', + '#description' => t('The ID of the thread that should be retrieved.') + ), + array( + '#name' => 'offset', + '#type' => 'int', + '#optional' => TRUE, + '#description' => t('Message offset from the start of the thread.') + ), + ), + '#return' => 'array', + '#help' => t('Get all messages in a thread. User needs to be logged in. Unless the logged-in user has the \'read all private messages\' permission, the user will only be able to get threads that he/she participated in.') + ), + ); +} Index: pm_service/pm_service.test =================================================================== RCS file: pm_service/pm_service.test diff -N pm_service/pm_service.test --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ pm_service/pm_service.test 3 Jan 2011 21:06:50 -0000 @@ -0,0 +1,212 @@ + 'Privatemsg Services functionality.', + 'description' => 'Ensure that the Privatemsg services integration functions properly.', + 'group' => 'Privatemsg', + 'dependencies' => array('services'), + ); + } + + /** + * setUp() performs any pre-requisite tasks that need to happen. + */ + public function setUp() { + // Must include every single module that PM Service module relies on. + parent::setUp('privatemsg', 'services', 'services_keyauth', 'pm_service'); + } + + /** + * Test pm.get service (get messages through services) + */ + public function testPrivatemsgServiceGet() { + + // Setup 2 users. + $author = $this->drupalCreateUser(array('write privatemsg')); + $recipient = $this->drupalCreateUser(array('administer services', 'access administration pages', 'get private messages from remote')); + + // Send 1st message to recipient. + $subject = 'My First Message'; + $body = $this->randomName(20); + privatemsg_new_thread(array($recipient), $subject, $body, array('author' => $author)); + + // Send 2nd message to recipient. + $subject = 'My Second Message'; + $body = $this->randomName(20); + privatemsg_new_thread(array($recipient), $subject, $body, array('author' => $author)); + + // Have recipient navigate to services browser page for pm.get and call the method. + $this->drupalLogin($recipient); + $this->drupalGet('admin/build/services/browse/pm.get'); + + // Have recipient click on the "Call method" button. + $this->drupalPost('admin/build/services/browse/pm.get', array(), t('Call method')); + + // Make sure the that the 1st messages is returned. + $this->assertRaw('My First Message', t('Verify that the custom title of thread #1 was found')); + + // Make sure the that the 1st messages is returned. + $this->assertRaw('My Second Message', t('Verify that the custom title of thread #2 was found')); + + } + + /** + * Test pm.getThread service (get thread through service) + */ + public function testPrivatemsgServiceGetThread() { + + // Setup 2 users + $author = $this->drupalCreateUser(array('write privatemsg')); + $recipient = $this->drupalCreateUser(array('administer services', 'access administration pages', 'get private messages from remote')); + + // Send 1 message to recipient + $subject = 'My First Message'; + $body = $this->randomName(20); + privatemsg_new_thread(array($recipient), $subject, $body, array('author' => $author)); + + // Have recipient navigate to services browser page for pm.get and call the method. + $this->drupalLogin($recipient); + $this->drupalGet('admin/build/services/browse/pm.getThread'); + + // Have recipient click on the "Call method" button. + $edit = array( + 'arg[0]' => db_result(db_query_range("SELECT thread_id FROM {pm_index} ORDER BY mid", 0, 1)), + ); + $this->drupalPost('admin/build/services/browse/pm.getThread', $edit, t('Call method')); + + // Make sure the that 2 messages are returned. + $this->assertRaw('My First Message', t('Verify that the custom title of thread #1 was found')); + + } + + /** + * Test pm.unreadCount service (determines the number of unread messages) + */ + public function testPrivatemsgServiceUnreadCount() { + + // Setup 2 users + $author = $this->drupalCreateUser(array('write privatemsg')); + $recipient = $this->drupalCreateUser(array('administer services', 'access administration pages', 'get private messages from remote')); + + // Send 2 messages to this user. + $subject = $this->randomName(20); + $subject2 = $this->randomName(20); + $body = $this->randomName(100); + $body2 = $this->randomName(100); + $this->pass("Send 2 messages to the recipient."); + privatemsg_new_thread(array($recipient), $subject, $body, array('author' => $author)); + privatemsg_new_thread(array($recipient), $subject2, $body2, array('author' => $author)); + + // Have recipient navigate to services browser page for pm.unreadCount and call the method. + $this->drupalLogin($recipient); + $this->drupalGet('admin/build/services/browse/pm.unreadCount'); + + // Have recipient click on the "Call method" button. + $this->drupalPost('admin/build/services/browse/pm.unreadCount', array(), t('Call method')); + + // Make sure the that 2 messages are returned. + $this->assertRaw('

Result

2
', t('Verify that the count of unread messages is "2".')); + + } + + /** + * Test pm.send service (create a new thread) + */ + public function testPrivatemsgServiceSend() { + + // Setup 2 users. + $author_permissions = array( + 'write privatemsg', + 'administer services', + 'access administration pages', + 'send private messages from remote', + ); + $author = $this->drupalCreateUser($author_permissions); + $recipient = $this->drupalCreateUser(array('read privatemsg')); + + // Have author navigate to services browser page for pm.send and call the method. + $this->drupalLogin($author); + $this->drupalGet('admin/build/services/browse/pm.send'); + + // Author sends a message to recipient through services. + $edit = array( + 'arg[0]' => $recipient->name, // Recipient name. + 'arg[1]' => 'Message Subject', // Message subject. + 'arg[2]' => 'Body of this messages', // Message body. + ); + $this->drupalPost('admin/build/services/browse/pm.send', $edit, t('Call method')); + + // Make sure the reply got sent out successfully. + $this->assertRaw('

Result

1
', t('Messages was successfully sent to recipient.')); + + } + + /** + * Test pm.send service (reply to a thread through services) + */ + public function testPrivatemsgServiceReply() { + + // Setup 2 users. + $author_permissions = array( + 'write privatemsg', + 'administer services', + 'access administration pages', + 'get private messages from remote', + ); + $author = $this->drupalCreateUser($author_permissions); + $recipient_permissions = array( + 'write privatemsg', + 'administer services', + 'access administration pages', + 'get private messages from remote', + 'send private messages from remote', + ); + $recipient = $this->drupalCreateUser($recipient_permissions); + + // Author sends a message to recipient. + $subject = 'My First Message'; + $body = $this->randomName(20); + privatemsg_new_thread(array($recipient), $subject, $body, array('author' => $author)); + + // Recipient logs in and navigates to the services admin page to send a message. + $this->drupalLogin($recipient); + $this->drupalGet('admin/build/services/browse/pm.reply'); + + // Recipient replies to the first thread sent by author. + $edit = array( + 'arg[0]' => 'This is my reply body.', + 'arg[1]' => db_result(db_query_range("SELECT thread_id FROM {pm_index} ORDER BY mid", 0, 1)), + ); + $this->drupalPost('admin/build/services/browse/pm.reply', $edit, t('Call method')); + + // Make sure the reply got sent out successfully. + $this->assertRaw('

Result

1
', t('Reply was successfully sent by recipient.')); + + // Login the author and make sure he received the reply (testing through services call). + $this->drupalLogin($author); + $this->drupalGet('admin/build/services/browse/pm.getThread'); + + // Have recipient click on the "Call method" button. + $edit = array( + 'arg[0]' => 1, + ); + $this->drupalPost('admin/build/services/browse/pm.getThread', $edit, t('Call method')); + + // Make sure the that the reply from the recipient is visible in thread #1. + $this->assertRaw('This is my reply', t('Verify that author received the reply from recipient.')); + + } + +}