Skip to content

Commit

Permalink
MDL-63466 core_message: Add conversation support to get_messages
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
sarjona authored and snake committed Oct 24, 2018
1 parent d89d0d6 commit fb04293
Show file tree
Hide file tree
Showing 11 changed files with 1,002 additions and 24 deletions.
2 changes: 1 addition & 1 deletion lang/en/cache.php
Expand Up @@ -55,7 +55,7 @@
$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';
Expand Down
4 changes: 2 additions & 2 deletions lib/db/caches.php
Expand Up @@ -342,10 +342,10 @@
'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',
),
Expand Down
9 changes: 9 additions & 0 deletions lib/db/services.php
Expand Up @@ -1127,6 +1127,15 @@
'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',
Expand Down
12 changes: 6 additions & 6 deletions lib/messagelib.php
Expand Up @@ -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.
Expand All @@ -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
*
Expand Down
69 changes: 67 additions & 2 deletions message/classes/api.php
Expand Up @@ -608,9 +608,17 @@ public static function get_messages($userid, $otheruserid, $limitfrom = 0, $limi
$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
Expand All @@ -623,13 +631,48 @@ public static function get_messages($userid, $otheruserid, $limitfrom = 0, $limi
$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.
*
Expand All @@ -649,6 +692,28 @@ public static function get_most_recent_message($userid, $otheruserid) {
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.
*
Expand Down
83 changes: 75 additions & 8 deletions message/classes/helper.php
Expand Up @@ -108,6 +108,76 @@ public static function get_messages($userid, $otheruserid, $timedeleted = 0, $li
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).
Expand Down Expand Up @@ -370,16 +440,13 @@ public static function get_conversation_hash(array $userids) {
}

/**
* 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;
}

/**
Expand Down
6 changes: 2 additions & 4 deletions message/classes/time_last_message_between_users.php
Expand Up @@ -28,7 +28,7 @@
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
Expand Down Expand Up @@ -61,9 +61,7 @@ public static function get_instance_for_cache(\cache_definition $definition) {
* @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;
Expand Down

0 comments on commit fb04293

Please sign in to comment.