MDL-63466 core_message: Add conversation support to get_messages

- The get_conversation_messages has been added to the API and the WS
with the conversation identifier (convid) instead of the userto,
to let get conversation messages and the members involved.
- The cache has been also reviewed, to use the convid instead of the
[userfrom, userto] keys.
- The get_most_recent_conversation_messages has been added to the API
to update the cache when needed.
This commit is contained in:
Sara Arjona 2018-10-23 13:18:49 +02:00 committed by Jake Dallimore
parent d89d0d6593
commit fb04293bb1
11 changed files with 1002 additions and 24 deletions

View File

@ -55,7 +55,7 @@ $string['cachedef_suspended_userids'] = 'List of suspended users per course';
$string['cachedef_groupdata'] = 'Course group information';
$string['cachedef_htmlpurifier'] = 'HTML Purifier - cleaned content';
$string['cachedef_langmenu'] = 'List of available languages';
$string['cachedef_message_time_last_message_between_users'] = 'Time created for most recent message between users';
$string['cachedef_message_time_last_message_between_users'] = 'Time created for most recent message in a conversation';
$string['cachedef_locking'] = 'Locking';
$string['cachedef_message_processors_enabled'] = "Message processors enabled status";
$string['cachedef_contextwithinsights'] = 'Context with insights';

View File

@ -342,10 +342,10 @@ $definitions = array(
'staticaccelerationsize' => 3
),
// Caches the time of the last message between two users.
// Caches the time of the last message in a conversation.
'message_time_last_message_between_users' => array(
'mode' => cache_store::MODE_APPLICATION,
'simplekeys' => true, // The id of the sender and recipient is used.
'simplekeys' => true, // The conversation id is used.
'simplevalues' => true,
'datasource' => '\core_message\time_last_message_between_users',
),

View File

@ -1127,6 +1127,15 @@ $functions = array(
'ajax' => true,
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
'core_message_get_conversation_messages' => array(
'classname' => 'core_message_external',
'methodname' => 'get_conversation_messages',
'classpath' => 'message/externallib.php',
'description' => 'Retrieve the conversation messages and relevant member information',
'type' => 'read',
'ajax' => true,
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
'core_message_unblock_user' => array(
'classname' => 'core_message_external',
'methodname' => 'unblock_user',

View File

@ -292,11 +292,12 @@ function message_send(\core\message\message $eventdata) {
// Only cache messages, not notifications.
if (!$eventdata->notification) {
// Cache the timecreated value of the last message between these two users.
$cache = cache::make('core', 'message_time_last_message_between_users');
$key = \core_message\helper::get_last_message_time_created_cache_key($eventdata->userfrom->id,
$eventdata->userto->id);
$cache->set($key, $tabledata->timecreated);
if (!empty($eventdata->convid)) {
// Cache the timecreated value of the last message in this conversation.
$cache = cache::make('core', 'message_time_last_message_between_users');
$key = \core_message\helper::get_last_message_time_created_cache_key($eventdata->convid);
$cache->set($key, $tabledata->timecreated);
}
}
// Store unread message just in case we get a fatal error any time later.
@ -307,7 +308,6 @@ function message_send(\core\message\message $eventdata) {
return \core\message\manager::send_message($eventdata, $tabledata, $processorlist);
}
/**
* Updates the message_providers table with the current set of message providers
*

View File

@ -608,9 +608,17 @@ class api {
$sort = 'timecreated ASC', $timefrom = 0, $timeto = 0) {
if (!empty($timefrom)) {
// Get the conversation between userid and otheruserid.
$userids = [$userid, $otheruserid];
if (!$conversationid = self::get_conversation_between_users($userids)) {
// This method was always used for individual conversations.
$conversation = self::create_conversation(self::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $userids);
$conversationid = $conversation->id;
}
// Check the cache to see if we even need to do a DB query.
$cache = \cache::make('core', 'message_time_last_message_between_users');
$key = helper::get_last_message_time_created_cache_key($otheruserid, $userid);
$key = helper::get_last_message_time_created_cache_key($conversationid);
$lastcreated = $cache->get($key);
// The last known message time is earlier than the one being requested so we can
@ -623,13 +631,48 @@ class api {
$arrmessages = array();
if ($messages = helper::get_messages($userid, $otheruserid, 0, $limitfrom, $limitnum,
$sort, $timefrom, $timeto)) {
$arrmessages = helper::create_messages($userid, $messages);
}
return $arrmessages;
}
/**
* Returns the messages for the defined conversation.
*
* @param int $userid The current user.
* @param int $convid The conversation where the messages belong. Could be an object or just the id.
* @param int $limitfrom Return a subset of records, starting at this point (optional).
* @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
* @param string $sort The column name to order by including optionally direction.
* @param int $timefrom The time from the message being sent.
* @param int $timeto The time up until the message being sent.
* @return array of messages
*/
public static function get_conversation_messages(int $userid, int $convid, int $limitfrom = 0, int $limitnum = 0,
string $sort = 'timecreated ASC', int $timefrom = 0, int $timeto = 0) : array {
if (!empty($timefrom)) {
// Check the cache to see if we even need to do a DB query.
$cache = \cache::make('core', 'message_time_last_message_between_users');
$key = helper::get_last_message_time_created_cache_key($convid);
$lastcreated = $cache->get($key);
// The last known message time is earlier than the one being requested so we can
// just return an empty result set rather than having to query the DB.
if ($lastcreated && $lastcreated < $timefrom) {
return [];
}
}
$arrmessages = array();
if ($messages = helper::get_conversation_messages($userid, $convid, 0, $limitfrom, $limitnum, $sort, $timefrom, $timeto)) {
$arrmessages = helper::format_conversation_messages($userid, $convid, $messages);
}
return $arrmessages;
}
/**
* Returns the most recent message between two users.
*
@ -649,6 +692,28 @@ class api {
return null;
}
/**
* Returns the most recent message in a conversation.
*
* @param int $convid The conversation identifier.
* @param int $currentuserid The current user identifier.
* @return \stdClass|null The most recent message.
*/
public static function get_most_recent_conversation_message(int $convid, int $currentuserid = 0) {
global $USER;
if (empty($currentuserid)) {
$currentuserid = $USER->id;
}
if ($messages = helper::get_conversation_messages($currentuserid, $convid, 0, 0, 1, 'timecreated DESC')) {
$convmessages = helper::format_conversation_messages($currentuserid, $convid, $messages);
return array_pop($convmessages['messages']);
}
return null;
}
/**
* Returns the profile information for a contact for a user.
*

View File

@ -108,6 +108,76 @@ class helper {
return $messages;
}
/**
* Helper function to retrieve conversation messages.
*
* @param int $userid The current user.
* @param int $convid The conversation identifier.
* @param int $timedeleted The time the message was deleted
* @param int $limitfrom Return a subset of records, starting at this point (optional).
* @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
* @param string $sort The column name to order by including optionally direction.
* @param int $timefrom The time from the message being sent.
* @param int $timeto The time up until the message being sent.
* @return array of messages
*/
public static function get_conversation_messages(int $userid, int $convid, int $timedeleted = 0, int $limitfrom = 0,
int $limitnum = 0, string $sort = 'timecreated ASC', int $timefrom = 0,
int $timeto = 0) : array {
global $DB;
$sql = "SELECT m.id, m.useridfrom, m.subject, m.fullmessage, m.fullmessagehtml,
m.fullmessageformat, m.smallmessage, m.timecreated, muaread.timecreated AS timeread
FROM {message_conversations} mc
INNER JOIN {messages} m
ON m.conversationid = mc.id
LEFT JOIN {message_user_actions} muaread
ON (muaread.messageid = m.id
AND muaread.userid = :userid1
AND muaread.action = :readaction)";
$params = ['userid1' => $userid, 'readaction' => api::MESSAGE_ACTION_READ, 'convid' => $convid];
if (empty($timedeleted)) {
$sql .= " LEFT JOIN {message_user_actions} mua
ON (mua.messageid = m.id
AND mua.userid = :userid2
AND mua.action = :deleteaction
AND mua.timecreated is NOT NULL)";
} else {
$sql .= " INNER JOIN {message_user_actions} mua
ON (mua.messageid = m.id
AND mua.userid = :userid2
AND mua.action = :deleteaction
AND mua.timecreated = :timedeleted)";
$params['timedeleted'] = $timedeleted;
}
$params['userid2'] = $userid;
$params['deleteaction'] = api::MESSAGE_ACTION_DELETED;
$sql .= " WHERE mc.id = :convid";
if (!empty($timefrom)) {
$sql .= " AND m.timecreated >= :timefrom";
$params['timefrom'] = $timefrom;
}
if (!empty($timeto)) {
$sql .= " AND m.timecreated <= :timeto";
$params['timeto'] = $timeto;
}
if (empty($timedeleted)) {
$sql .= " AND mua.id is NULL";
}
$sql .= " ORDER BY m.$sort";
$messages = $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
return $messages;
}
/**
* Helper function to return a conversation messages with the involved members (only the ones
* who have sent any of these messages).
@ -370,16 +440,13 @@ class helper {
}
/**
* Returns the cache key for the time created value of the last message between two users.
* Returns the cache key for the time created value of the last message of this conversation.
*
* @param int $userid
* @param int $user2id
* @return string
* @param int $convid The conversation identifier.
* @return string The key.
*/
public static function get_last_message_time_created_cache_key($userid, $user2id) {
$ids = [$userid, $user2id];
sort($ids);
return implode('_', $ids);
public static function get_last_message_time_created_cache_key(int $convid) {
return $convid;
}
/**

View File

@ -28,7 +28,7 @@ namespace core_message;
defined('MOODLE_INTERNAL') || die();
/**
* Cache data source for the time of the last message between users.
* Cache data source for the time of the last message in a conversation.
*
* @package core_message
* @category cache
@ -61,9 +61,7 @@ class time_last_message_between_users implements \cache_data_source {
* @return mixed What ever data should be returned, or false if it can't be loaded.
*/
public function load_for_cache($key) {
list($userid1, $userid2) = explode('_', $key);
$message = api::get_most_recent_message($userid1, $userid2);
$message = api::get_most_recent_conversation_message($key);
if ($message) {
return $message->timecreated;

View File

@ -868,6 +868,44 @@ class core_message_external extends external_api {
);
}
/**
* Return the structure of a conversation member.
*
* @return external_single_structure
* @since Moodle 3.6
*/
private static function get_conversation_member_structure() {
return new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'The user id'),
'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?')
)
);
}
/**
* Return the structure of a message area message.
*
* @return external_single_structure
* @since Moodle 3.6
*/
private static function get_conversation_message_structure() {
return new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'The id of the message'),
'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
'text' => new external_value(PARAM_RAW, 'The text of the message'),
'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
)
);
}
/**
* Return the structure of a message area message.
*
@ -1373,6 +1411,108 @@ class core_message_external extends external_api {
);
}
/**
* The conversation messages parameters.
*
* @return external_function_parameters
* @since 3.6
*/
public static function get_conversation_messages_parameters() {
return new external_function_parameters(
array(
'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
'convid' => new external_value(PARAM_INT, 'The conversation id'),
'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
'timefrom' => new external_value(PARAM_INT,
'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
)
);
}
/**
* Get conversation messages.
*
* @param int $currentuserid The current user's id.
* @param int $convid The conversation id.
* @param int $limitfrom Return a subset of records, starting at this point (optional).
* @param int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
* @param bool $newest True for getting first newest messages, false otherwise.
* @param int $timefrom The time from the conversation messages to get.
* @return stdClass The messages and members who have sent some of these messages.
* @throws moodle_exception
* @since 3.6
*/
public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
bool $newest = false, int $timefrom = 0) {
global $CFG, $PAGE, $USER;
// Check if messaging is enabled.
if (empty($CFG->messaging)) {
throw new moodle_exception('disabled', 'message');
}
$systemcontext = context_system::instance();
$params = array(
'currentuserid' => $currentuserid,
'convid' => $convid,
'limitfrom' => $limitfrom,
'limitnum' => $limitnum,
'newest' => $newest,
'timefrom' => $timefrom,
);
self::validate_parameters(self::get_conversation_messages_parameters(), $params);
self::validate_context($systemcontext);
if (($USER->id != $currentuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
throw new moodle_exception('You do not have permission to perform this action.');
}
$sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
// We need to enforce a one second delay on messages to avoid race conditions of current
// messages still being sent.
//
// There is a chance that we could request messages before the current time's
// second has elapsed and while other messages are being sent in that same second. In which
// case those messages will be lost.
//
// Instead we ignore the current time in the result set to ensure that second is allowed to finish.
$timeto = empty($timefrom) ? 0 : time() - 1;
// No requesting messages from the current time, as stated above.
if ($timefrom == time()) {
$messages = [];
} else {
$messages = \core_message\api::get_conversation_messages($currentuserid, $convid, $limitfrom,
$limitnum, $sort, $timefrom, $timeto);
}
return $messages;
}
/**
* The messagearea messages return structure.
*
* @return external_single_structure
* @since 3.6
*/
public static function get_conversation_messages_returns() {
return new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'The conversation id'),
'members' => new external_multiple_structure(
self::get_conversation_member_structure()
),
'messages' => new external_multiple_structure(
self::get_conversation_message_structure()
),
)
);
}
/**
* The get most recent message return parameters.
*

View File

@ -29,6 +29,8 @@ global $CFG;
require_once($CFG->dirroot . '/message/tests/messagelib_test.php');
use \core_message\tests\helper as testhelper;
/**
* Test message API.
*
@ -1351,6 +1353,411 @@ class core_message_api_testcase extends core_message_messagelib_testcase {
$this->assertContains('Word.', $message4->text);
}
/**
* Tests retrieving conversation messages.
*/
public function test_get_conversation_messages() {
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
// Create conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
[$user1->id, $user2->id]
);
// The person doing the search.
$this->setUser($user1);
// Send some messages back and forth.
$time = 1;
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
// Retrieve the messages.
$convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id);
// Confirm the conversation id is correct.
$this->assertEquals($conversation->id, $convmessages['id']);
// Confirm the message data is correct.
$messages = $convmessages['messages'];
$this->assertEquals(4, count($messages));
$message1 = $messages[0];
$message2 = $messages[1];
$message3 = $messages[2];
$message4 = $messages[3];
$this->assertEquals($user1->id, $message1->useridfrom);
$this->assertContains('Yo!', $message1->text);
$this->assertEquals($user2->id, $message2->useridfrom);
$this->assertContains('Sup mang?', $message2->text);
$this->assertEquals($user1->id, $message3->useridfrom);
$this->assertContains('Writing PHPUnit tests!', $message3->text);
$this->assertEquals($user1->id, $message4->useridfrom);
$this->assertContains('Word.', $message4->text);
// Confirm the members data is correct.
$members = $convmessages['members'];
$this->assertEquals(2, count($members));
}
/**
* Tests retrieving group conversation messages.
*/
public function test_get_group_conversation_messages() {
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
$user4 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id, $user4->id]
);
// The person doing the search.
$this->setUser($user1);
// Send some messages back and forth.
$time = 1;
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Yeah!', $time + 5);
// Retrieve the messages.
$convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id);
// Confirm the conversation id is correct.
$this->assertEquals($conversation->id, $convmessages['id']);
// Confirm the message data is correct.
$messages = $convmessages['messages'];
$this->assertEquals(5, count($messages));
$message1 = $messages[0];
$message2 = $messages[1];
$message3 = $messages[2];
$message4 = $messages[3];
$message5 = $messages[4];
$this->assertEquals($user1->id, $message1->useridfrom);
$this->assertContains('Yo!', $message1->text);
$this->assertEquals($user2->id, $message2->useridfrom);
$this->assertContains('Sup mang?', $message2->text);
$this->assertEquals($user3->id, $message3->useridfrom);
$this->assertContains('Writing PHPUnit tests!', $message3->text);
$this->assertEquals($user1->id, $message4->useridfrom);
$this->assertContains('Word.', $message4->text);
$this->assertEquals($user2->id, $message5->useridfrom);
$this->assertContains('Yeah!', $message5->text);
// Confirm the members data is correct.
$members = $convmessages['members'];
$this->assertEquals(3, count($members));
}
/**
* Test retrieving conversation messages by providing a minimum timecreated value.
*/
public function test_get_conversation_messages_time_from_only() {
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
$user4 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id, $user4->id]
);
// The person doing the search.
$this->setUser($user1);
// Send some messages back and forth.
$time = 1;
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
// Retrieve the messages from $time, which should be all of them.
$convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC', $time);
// Confirm the conversation id is correct.
$this->assertEquals($conversation->id, $convmessages['id']);
// Confirm the message data is correct.
$messages = $convmessages['messages'];
$this->assertEquals(4, count($messages));
$message1 = $messages[0];
$message2 = $messages[1];
$message3 = $messages[2];
$message4 = $messages[3];
$this->assertContains('Message 1', $message1->text);
$this->assertContains('Message 2', $message2->text);
$this->assertContains('Message 3', $message3->text);
$this->assertContains('Message 4', $message4->text);
// Confirm the members data is correct.
$members = $convmessages['members'];
$this->assertEquals(3, count($members));
// Retrieve the messages from $time + 3, which should only be the 2 last messages.
$convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0,
'timecreated ASC', $time + 3);
// Confirm the conversation id is correct.
$this->assertEquals($conversation->id, $convmessages['id']);
// Confirm the message data is correct.
$messages = $convmessages['messages'];
$this->assertEquals(2, count($messages));
$message1 = $messages[0];
$message2 = $messages[1];
$this->assertContains('Message 3', $message1->text);
$this->assertContains('Message 4', $message2->text);
// Confirm the members data is correct.
$members = $convmessages['members'];
$this->assertEquals(2, count($members));
}
/**
* Test retrieving conversation messages by providing a maximum timecreated value.
*/
public function test_get_conversation_messages_time_to_only() {
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
$user4 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id, $user4->id]
);
// The person doing the search.
$this->setUser($user1);
// Send some messages back and forth.
$time = 1;
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
// Retrieve the messages up until $time + 4, which should be all of them.
$convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC',
0, $time + 4);
// Confirm the conversation id is correct.
$this->assertEquals($conversation->id, $convmessages['id']);
// Confirm the message data is correct.
$messages = $convmessages['messages'];
$this->assertEquals(4, count($messages));
$message1 = $messages[0];
$message2 = $messages[1];
$message3 = $messages[2];
$message4 = $messages[3];
$this->assertContains('Message 1', $message1->text);
$this->assertContains('Message 2', $message2->text);
$this->assertContains('Message 3', $message3->text);
$this->assertContains('Message 4', $message4->text);
// Confirm the members data is correct.
$members = $convmessages['members'];
$this->assertEquals(3, count($members));
// Retrieve the messages up until $time + 2, which should be the first two.
$convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC',
0, $time + 2);
// Confirm the conversation id is correct.
$this->assertEquals($conversation->id, $convmessages['id']);
// Confirm the message data is correct.
$messages = $convmessages['messages'];
$this->assertEquals(2, count($messages));
$message1 = $messages[0];
$message2 = $messages[1];
$this->assertContains('Message 1', $message1->text);
$this->assertContains('Message 2', $message2->text);
// Confirm the members data is correct.
$members = $convmessages['members'];
$this->assertEquals(2, count($members));
}
/**
* Test retrieving conversation messages by providing a minimum and maximum timecreated value.
*/
public function test_get_conversation_messages_time_from_and_to() {
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
$user4 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id, $user4->id]
);
// The person doing the search.
$this->setUser($user1);
// Send some messages back and forth.
$time = 1;
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
// Retrieve the messages from $time + 2 up until $time + 3, which should be 2nd and 3rd message.
$convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0,
'timecreated ASC', $time + 2, $time + 3);
// Confirm the conversation id is correct.
$this->assertEquals($conversation->id, $convmessages['id']);
// Confirm the message data is correct.
$messages = $convmessages['messages'];
$this->assertEquals(2, count($messages));
$message1 = $messages[0];
$message2 = $messages[1];
$this->assertContains('Message 2', $message1->text);
$this->assertContains('Message 3', $message2->text);
// Confirm the members data is correct.
$members = $convmessages['members'];
$this->assertEquals(2, count($members));
}
/**
* Test retrieving conversation messages by providing a limitfrom value.
*/
public function test_get_conversation_messages_limitfrom_only() {
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
$user4 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id, $user4->id]
);
// The person doing the search.
$this->setUser($user1);
// Send some messages back and forth.
$time = 1;
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
// Retrieve the messages from $time, which should be all of them.
$convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 2);
// Confirm the conversation id is correct.
$messages = $convmessages['messages'];
$this->assertEquals($conversation->id, $convmessages['id']);
// Confirm the message data is correct.
$this->assertEquals(2, count($messages));
$message1 = $messages[0];
$message2 = $messages[1];
$this->assertContains('Message 3', $message1->text);
$this->assertContains('Message 4', $message2->text);
// Confirm the members data is correct.
$members = $convmessages['members'];
$this->assertEquals(2, count($members));
}
/**
* Test retrieving conversation messages by providing a limitnum value.
*/
public function test_get_conversation_messages_limitnum() {
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
$user4 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id, $user4->id]
);
// The person doing the search.
$this->setUser($user1);
// Send some messages back and forth.
$time = 1;
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
// Retrieve the messages from $time, which should be all of them.
$convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 2, 1);
// Confirm the conversation id is correct.
$messages = $convmessages['messages'];
$this->assertEquals($conversation->id, $convmessages['id']);
// Confirm the message data is correct.
$messages = $convmessages['messages'];
$this->assertEquals(1, count($messages));
$message1 = $messages[0];
$this->assertContains('Message 3', $message1->text);
// Confirm the members data is correct.
$members = $convmessages['members'];
$this->assertEquals(1, count($members));
}
/**
* Tests retrieving most recent message.
*/
@ -1378,6 +1785,39 @@ class core_message_api_testcase extends core_message_messagelib_testcase {
$this->assertContains('Word.', $message->text);
}
/**
* Tests retrieving most recent conversation message.
*/
public function test_get_most_recent_conversation_message() {
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id]
);
// The person getting the most recent conversation message.
$this->setUser($user1);
// Send some messages back and forth.
$time = 1;
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Word.', $time + 4);
// Retrieve the most recent messages.
$message = \core_message\api::get_most_recent_conversation_message($conversation->id, $user1->id);
// Check the results are correct.
$this->assertEquals($user2->id, $message->useridfrom);
$this->assertContains('Word.', $message->text);
}
/**
* Tests retrieving a user's profile.
*/

View File

@ -30,6 +30,8 @@ global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
require_once($CFG->dirroot . '/message/externallib.php');
use \core_message\tests\helper as testhelper;
class core_message_externallib_testcase extends externallib_advanced_testcase {
/**
@ -2971,6 +2973,263 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
core_message_external::data_for_messagearea_messages($user1->id, $user2->id);
}
/**
* Tests get_conversation_messages for retrieving messages.
*/
public function test_get_conversation_messages() {
$this->resetAfterTest(true);
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
$user4 = self::getDataGenerator()->create_user();
$user5 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id, $user4->id]
);
// The person asking for the messages.
$this->setUser($user1);
// Send some messages back and forth.
$time = time();
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time);
testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Sup mang?', $time + 1);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Writing PHPUnit tests!', $time + 2);
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 3);
// Retrieve the messages.
$result = core_message_external::get_conversation_messages($user1->id, $conversation->id);
// We need to execute the return values cleaning process to simulate the web service server.
$result = external_api::clean_returnvalue(core_message_external::get_conversation_messages_returns(),
$result);
// Check the results are correct.
$this->assertEquals($conversation->id, $result['id']);
// Confirm the members data is correct.
$members = $result['members'];
$this->assertCount(3, $members);
$membersid = [$members[0]['id'], $members[1]['id'], $members[2]['id']];
$this->assertContains($user1->id, $membersid);
$this->assertContains($user2->id, $membersid);
$this->assertContains($user3->id, $membersid);
$this->assertNotContains($user4->id, $membersid);
$this->assertNotContains($user5->id, $membersid);
$membersfullnames = [$members[0]['fullname'], $members[1]['fullname'], $members[2]['fullname']];
$this->assertContains(fullname($user1), $membersfullnames);
$this->assertContains(fullname($user2), $membersfullnames);
$this->assertContains(fullname($user3), $membersfullnames);
$this->assertNotContains(fullname($user4), $membersfullnames);
$this->assertNotContains(fullname($user5), $membersfullnames);
// Confirm the messages data is correct.
$messages = $result['messages'];
$this->assertCount(4, $messages);
$message1 = $messages[0];
$message2 = $messages[1];
$message3 = $messages[2];
$message4 = $messages[3];
$this->assertEquals($user1->id, $message1['useridfrom']);
$this->assertContains('Yo!', $message1['text']);
$this->assertEquals($user3->id, $message2['useridfrom']);
$this->assertContains('Sup mang?', $message2['text']);
$this->assertEquals($user2->id, $message3['useridfrom']);
$this->assertContains('Writing PHPUnit tests!', $message3['text']);
$this->assertEquals($user1->id, $message4['useridfrom']);
$this->assertContains('Word.', $message4['text']);
}
/**
* Tests get_conversation_messages for retrieving messages using timefrom parameter.
*/
public function test_get_conversation_messages_timefrom() {
$this->resetAfterTest(true);
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
$user4 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id]
);
// The person asking for the messages.
$this->setUser($user1);
// Send some messages back and forth.
$time = time();
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time - 4);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time - 3);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 3', $time - 2);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 4', $time - 1);
// Retrieve the messages from $time - 3, which should be the 3 most recent messages.
$result = core_message_external::get_conversation_messages($user1->id, $conversation->id, 0, 0, false, $time - 3);
// We need to execute the return values cleaning process to simulate the web service server.
$result = external_api::clean_returnvalue(core_message_external::get_conversation_messages_returns(),
$result);
// Check the results are correct.
$this->assertEquals($conversation->id, $result['id']);
// Confirm the messages data is correct.
$messages = $result['messages'];
$this->assertCount(3, $messages);
$message1 = $messages[0];
$message2 = $messages[1];
$message3 = $messages[2];
$this->assertContains('Message 2', $message1['text']);
$this->assertContains('Message 3', $message2['text']);
$this->assertContains('Message 4', $message3['text']);
// Confirm the members data is correct.
$members = $result['members'];
$this->assertCount(1, $members);
$this->assertEquals($user2->id, $members[0]['id']);
}
/**
* Tests get_conversation_messages for retrieving messages as another user.
*/
public function test_get_conversation_messages_as_other_user() {
$this->resetAfterTest(true);
// Set as admin.
$this->setAdminUser();
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
$user4 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id, $user4->id]
);
// Send some messages back and forth.
$time = time();
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time);
testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Sup mang?', $time + 1);
testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Writing PHPUnit tests!', $time + 2);
testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 3);
// Retrieve the messages.
$result = core_message_external::get_conversation_messages($user1->id, $conversation->id);
// We need to execute the return values cleaning process to simulate the web service server.
$result = external_api::clean_returnvalue(core_message_external::get_conversation_messages_returns(),
$result);
// Check the results are correct.
$this->assertEquals($conversation->id, $result['id']);
// Confirm the members data is correct.
$members = $result['members'];
$this->assertCount(3, $members);
$membersid = [$members[0]['id'], $members[1]['id'], $members[2]['id']];
$this->assertContains($user1->id, $membersid);
$this->assertContains($user2->id, $membersid);
$this->assertContains($user3->id, $membersid);
$this->assertNotContains($user4->id, $membersid);
// Confirm the message data is correct.
$messages = $result['messages'];
$this->assertCount(4, $messages);
$message1 = $messages[0];
$message2 = $messages[1];
$message3 = $messages[2];
$message4 = $messages[3];
$this->assertEquals($user1->id, $message1['useridfrom']);
$this->assertContains('Yo!', $message1['text']);
$this->assertEquals($user3->id, $message2['useridfrom']);
$this->assertContains('Sup mang?', $message2['text']);
$this->assertEquals($user2->id, $message3['useridfrom']);
$this->assertContains('Writing PHPUnit tests!', $message3['text']);
$this->assertEquals($user1->id, $message4['useridfrom']);
$this->assertContains('Word.', $message4['text']);
}
/**
* Tests get_conversation_messages for retrieving messages as another user without the proper capabilities.
*/
public function test_get_conversation_messages_as_other_user_without_cap() {
$this->resetAfterTest(true);
// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
$user4 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id, $user4->id]
);
// The person asking for the messages for another user.
$this->setUser($user1);
// Ensure an exception is thrown.
$this->expectException('moodle_exception');
core_message_external::get_conversation_messages($user2->id, $conversation->id);
}
/**
* Tests get_conversation_messages for retrieving messages with messaging disabled.
*/
public function test_get_conversation_messages_messaging_disabled() {
$this->resetAfterTest(true);
// Create some skeleton data just so we can call the WS.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();
$user4 = self::getDataGenerator()->create_user();
// Create group conversation.
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
[$user1->id, $user2->id, $user3->id, $user4->id]
);
// The person asking for the messages for another user.
$this->setUser($user1);
// Disable messaging.
set_config('messaging', 0);
// Ensure an exception is thrown.
$this->expectException('moodle_exception');
core_message_external::get_conversation_messages($user1->id, $conversation->id);
}
/**
* Tests retrieving most recent message.
*/

View File

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2018102300.01; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2018102300.02; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.