mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 05:58:34 +01:00
MDL-63303 message: add get_conversation to message api
This commit is contained in:
parent
6399c7ef14
commit
4e3130269c
@ -1087,6 +1087,15 @@ $functions = array(
|
||||
'type' => 'read',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
|
||||
),
|
||||
'core_message_get_conversation' => array(
|
||||
'classname' => 'core_message_external',
|
||||
'methodname' => 'get_conversation',
|
||||
'classpath' => 'message/externallib.php',
|
||||
'description' => 'Retrieve a conversation for a user',
|
||||
'type' => 'read',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
|
||||
'ajax' => true
|
||||
),
|
||||
'core_message_get_messages' => array(
|
||||
'classname' => 'core_message_external',
|
||||
'methodname' => 'get_messages',
|
||||
|
@ -801,6 +801,121 @@ class api {
|
||||
return $DB->get_records_sql($sql, array('userid1' => $userid1, 'userid2' => $userid2), $limitfrom, $limitnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a conversation.
|
||||
*
|
||||
* @param int $userid The user id to get the conversation for
|
||||
* @param int $conversationid The id of the conversation to fetch
|
||||
* @param bool $includecontactrequests Should contact requests be included between members
|
||||
* @param bool $includeprivacyinfo Should privacy info be included between members
|
||||
* @param int $memberlimit Limit number of members to load
|
||||
* @param int $memberoffset Offset members by this amount
|
||||
* @param int $messagelimit Limit number of messages to load
|
||||
* @param int $messageoffset Offset the messages
|
||||
* @param bool $newestmessagesfirst Order messages by newest first
|
||||
* @return \stdClass
|
||||
*/
|
||||
public static function get_conversation(
|
||||
int $userid,
|
||||
int $conversationid,
|
||||
bool $includecontactrequests = false,
|
||||
bool $includeprivacyinfo = false,
|
||||
int $memberlimit = 0,
|
||||
int $memberoffset = 0,
|
||||
int $messagelimit = 0,
|
||||
int $messageoffset = 0,
|
||||
bool $newestmessagesfirst = true
|
||||
) {
|
||||
global $USER, $DB;
|
||||
|
||||
$systemcontext = \context_system::instance();
|
||||
$canreadallmessages = has_capability('moodle/site:readallmessages', $systemcontext);
|
||||
if (($USER->id != $userid) && !$canreadallmessages) {
|
||||
throw new \moodle_exception('You do not have permission to perform this action.');
|
||||
}
|
||||
|
||||
$conversation = $DB->get_record('message_conversations', ['id' => $conversationid]);
|
||||
if (!$conversation) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$isconversationmember = $DB->record_exists(
|
||||
'message_conversation_members',
|
||||
[
|
||||
'conversationid' => $conversationid,
|
||||
'userid' => $userid
|
||||
]
|
||||
);
|
||||
|
||||
if (!$isconversationmember && !$canreadallmessages) {
|
||||
throw new \moodle_exception('You do not have permission to view this conversation.');
|
||||
}
|
||||
|
||||
$members = self::get_conversation_members(
|
||||
$userid,
|
||||
$conversationid,
|
||||
$includecontactrequests,
|
||||
$memberoffset,
|
||||
$memberlimit
|
||||
);
|
||||
// Strip out the requesting user to match what get_conversations does.
|
||||
$members = array_filter($members, function($member) use ($userid) {
|
||||
return $member->id != $userid;
|
||||
});
|
||||
|
||||
$messages = self::get_conversation_messages(
|
||||
$userid,
|
||||
$conversationid,
|
||||
$messageoffset,
|
||||
$messagelimit,
|
||||
$newestmessagesfirst ? 'timecreated DESC' : 'timecreated ASC'
|
||||
);
|
||||
|
||||
$service = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($userid));
|
||||
$isfavourite = $service->favourite_exists('core_message', 'message_conversations', $conversationid, $systemcontext);
|
||||
|
||||
$convextrafields = self::get_linked_conversation_extra_fields([$conversation]);
|
||||
$subname = isset($convextrafields[$conversationid]) ? $convextrafields[$conversationid]['subname'] : null;
|
||||
$imageurl = isset($convextrafields[$conversationid]) ? $convextrafields[$conversationid]['imageurl'] : null;
|
||||
|
||||
$unreadcountssql = 'SELECT count(m.id)
|
||||
FROM {messages} m
|
||||
INNER JOIN {message_conversations} mc
|
||||
ON mc.id = m.conversationid
|
||||
LEFT JOIN {message_user_actions} mua
|
||||
ON (mua.messageid = m.id AND mua.userid = ? AND
|
||||
(mua.action = ? OR mua.action = ?))
|
||||
WHERE m.conversationid = ?
|
||||
AND m.useridfrom != ?
|
||||
AND mua.id is NULL';
|
||||
$unreadcount = $DB->count_records_sql(
|
||||
$unreadcountssql,
|
||||
[
|
||||
$userid,
|
||||
self::MESSAGE_ACTION_READ,
|
||||
self::MESSAGE_ACTION_DELETED,
|
||||
$conversationid,
|
||||
$userid
|
||||
]
|
||||
);
|
||||
|
||||
$membercount = $DB->count_records('message_conversation_members', ['conversationid' => $conversationid]);
|
||||
|
||||
return (object) [
|
||||
'id' => $conversation->id,
|
||||
'name' => $conversation->name,
|
||||
'subname' => $subname,
|
||||
'imageurl' => $imageurl,
|
||||
'type' => $conversation->type,
|
||||
'membercount' => $membercount,
|
||||
'isfavourite' => $isfavourite,
|
||||
'isread' => empty($unreadcount),
|
||||
'unreadcount' => $unreadcount,
|
||||
'members' => $members,
|
||||
'messages' => $messages['messages']
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a conversation as a favourite for the given user.
|
||||
*
|
||||
|
@ -1050,7 +1050,6 @@ class core_message_external extends external_api {
|
||||
* @return external_single_structure
|
||||
* @since Moodle 3.6
|
||||
*/
|
||||
|
||||
private static function get_conversation_structure() {
|
||||
return new external_single_structure(
|
||||
array(
|
||||
@ -1616,6 +1615,106 @@ class core_message_external extends external_api {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get conversation parameters.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function get_conversation_parameters() {
|
||||
return new external_function_parameters(
|
||||
array(
|
||||
'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
|
||||
'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'),
|
||||
'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
|
||||
'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
|
||||
'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
|
||||
'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
|
||||
'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
|
||||
'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
|
||||
'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single conversation.
|
||||
*
|
||||
* @param int $userid The user id to get the conversation for
|
||||
* @param int $conversationid The id of the conversation to fetch
|
||||
* @param bool $includecontactrequests Should contact requests be included between members
|
||||
* @param bool $includeprivacyinfo Should privacy info be included between members
|
||||
* @param int $memberlimit Limit number of members to load
|
||||
* @param int $memberoffset Offset members by this amount
|
||||
* @param int $messagelimit Limit number of messages to load
|
||||
* @param int $messageoffset Offset the messages
|
||||
* @param bool $newestmessagesfirst Order messages by newest first
|
||||
* @return stdClass
|
||||
* @throws \moodle_exception if the messaging feature is disabled on the site.
|
||||
*/
|
||||
public static function get_conversation(
|
||||
int $userid,
|
||||
int $conversationid,
|
||||
bool $includecontactrequests = false,
|
||||
bool $includeprivacyinfo = false,
|
||||
int $memberlimit = 0,
|
||||
int $memberoffset = 0,
|
||||
int $messagelimit = 0,
|
||||
int $messageoffset = 0,
|
||||
bool $newestmessagesfirst = true
|
||||
) {
|
||||
global $CFG, $DB, $USER;
|
||||
|
||||
// All the standard BL checks.
|
||||
if (empty($CFG->messaging)) {
|
||||
throw new moodle_exception('disabled', 'message');
|
||||
}
|
||||
|
||||
$params = [
|
||||
'userid' => $userid,
|
||||
'conversationid' => $conversationid,
|
||||
'includecontactrequests' => $includecontactrequests,
|
||||
'includeprivacyinfo' => $includeprivacyinfo,
|
||||
'memberlimit' => $memberlimit,
|
||||
'memberoffset' => $memberoffset,
|
||||
'messagelimit' => $messagelimit,
|
||||
'messageoffset' => $messageoffset,
|
||||
'newestmessagesfirst' => $newestmessagesfirst
|
||||
];
|
||||
self::validate_parameters(self::get_conversation_parameters(), $params);
|
||||
|
||||
$systemcontext = context_system::instance();
|
||||
self::validate_context($systemcontext);
|
||||
|
||||
$conversation = \core_message\api::get_conversation(
|
||||
$params['userid'],
|
||||
$params['conversationid'],
|
||||
$params['includecontactrequests'],
|
||||
$params['includeprivacyinfo'],
|
||||
$params['memberlimit'],
|
||||
$params['memberoffset'],
|
||||
$params['messagelimit'],
|
||||
$params['messageoffset'],
|
||||
$params['newestmessagesfirst']
|
||||
);
|
||||
|
||||
if ($conversation) {
|
||||
return $conversation;
|
||||
} else {
|
||||
// We have to throw an exception here because the external functions annoyingly
|
||||
// don't accept null to be returned for a single structure.
|
||||
throw new \moodle_exception('Conversation does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get conversation returns.
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function get_conversation_returns() {
|
||||
return self::get_conversation_structure();
|
||||
}
|
||||
|
||||
/**
|
||||
* The messagearea conversations parameters.
|
||||
*
|
||||
|
@ -5632,4 +5632,185 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
|
||||
$this->expectException(\moodle_exception::class);
|
||||
$writtenmessages = core_message_external::send_messages_to_conversation($gc1->id, $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting a conversation that doesn't exist.
|
||||
*/
|
||||
public function test_get_conversation_no_conversation() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user1 = self::getDataGenerator()->create_user();
|
||||
$user2 = self::getDataGenerator()->create_user();
|
||||
|
||||
$name = 'lol conversation';
|
||||
$conversation = \core_message\api::create_conversation(
|
||||
\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
|
||||
[
|
||||
$user1->id,
|
||||
$user2->id,
|
||||
],
|
||||
$name
|
||||
);
|
||||
$conversationid = $conversation->id;
|
||||
|
||||
$this->setUser($user1);
|
||||
|
||||
$this->expectException('moodle_exception');
|
||||
$conv = core_message_external::get_conversation($user1->id, $conversationid + 1);
|
||||
external_api::clean_returnvalue(core_message_external::get_conversation_returns(), $conv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting a conversation with no messages.
|
||||
*/
|
||||
public function test_get_conversation_no_messages() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user1 = self::getDataGenerator()->create_user();
|
||||
$user2 = self::getDataGenerator()->create_user();
|
||||
|
||||
$name = 'lol conversation';
|
||||
$conversation = \core_message\api::create_conversation(
|
||||
\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
|
||||
[
|
||||
$user1->id,
|
||||
$user2->id,
|
||||
],
|
||||
$name
|
||||
);
|
||||
$conversationid = $conversation->id;
|
||||
|
||||
$this->setUser($user1);
|
||||
|
||||
$conv = core_message_external::get_conversation($user1->id, $conversationid);
|
||||
external_api::clean_returnvalue(core_message_external::get_conversation_returns(), $conv);
|
||||
|
||||
$conv = (array) $conv;
|
||||
$this->assertEquals($conversationid, $conv['id']);
|
||||
$this->assertEquals($name, $conv['name']);
|
||||
$this->assertArrayHasKey('subname', $conv);
|
||||
$this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conv['type']);
|
||||
$this->assertEquals(2, $conv['membercount']);
|
||||
$this->assertEquals(false, $conv['isfavourite']);
|
||||
$this->assertEquals(true, $conv['isread']);
|
||||
$this->assertEquals(0, $conv['unreadcount']);
|
||||
$this->assertCount(1, $conv['members']);
|
||||
foreach ($conv['members'] as $member) {
|
||||
$member = (array) $member;
|
||||
$this->assertArrayHasKey('id', $member);
|
||||
$this->assertArrayHasKey('fullname', $member);
|
||||
$this->assertArrayHasKey('profileimageurl', $member);
|
||||
$this->assertArrayHasKey('profileimageurlsmall', $member);
|
||||
$this->assertArrayHasKey('isonline', $member);
|
||||
$this->assertArrayHasKey('showonlinestatus', $member);
|
||||
$this->assertArrayHasKey('isblocked', $member);
|
||||
$this->assertArrayHasKey('iscontact', $member);
|
||||
}
|
||||
$this->assertEmpty($conv['messages']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting a conversation with messages.
|
||||
*/
|
||||
public function test_get_conversation_with_messages() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user1 = self::getDataGenerator()->create_user();
|
||||
$user2 = self::getDataGenerator()->create_user();
|
||||
|
||||
// Some random conversation.
|
||||
$otherconversation = \core_message\api::create_conversation(
|
||||
\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
|
||||
[
|
||||
$user1->id,
|
||||
$user2->id,
|
||||
]
|
||||
);
|
||||
|
||||
$conversation = \core_message\api::create_conversation(
|
||||
\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
|
||||
[
|
||||
$user1->id,
|
||||
$user2->id,
|
||||
]
|
||||
);
|
||||
$conversationid = $conversation->id;
|
||||
|
||||
$time = time();
|
||||
$message1id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'A', $time - 10);
|
||||
$message2id = testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'B', $time - 5);
|
||||
$message3id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'C', $time);
|
||||
|
||||
// Add some messages to the other convo to make sure they aren't included.
|
||||
testhelper::send_fake_message_to_conversation($user1, $otherconversation->id, 'foo');
|
||||
|
||||
$this->setUser($user1);
|
||||
|
||||
// Test newest first.
|
||||
$conv = core_message_external::get_conversation(
|
||||
$user1->id,
|
||||
$conversationid,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
true
|
||||
);
|
||||
external_api::clean_returnvalue(core_message_external::get_conversation_returns(), $conv);
|
||||
|
||||
$conv = (array) $conv;
|
||||
$this->assertEquals(false, $conv['isread']);
|
||||
$this->assertEquals(1, $conv['unreadcount']);
|
||||
$this->assertCount(3, $conv['messages']);
|
||||
$this->assertEquals($message3id, $conv['messages'][0]->id);
|
||||
$this->assertEquals($user1->id, $conv['messages'][0]->useridfrom);
|
||||
$this->assertEquals($message2id, $conv['messages'][1]->id);
|
||||
$this->assertEquals($user2->id, $conv['messages'][1]->useridfrom);
|
||||
$this->assertEquals($message1id, $conv['messages'][2]->id);
|
||||
$this->assertEquals($user1->id, $conv['messages'][2]->useridfrom);
|
||||
|
||||
// Test newest last.
|
||||
$conv = core_message_external::get_conversation(
|
||||
$user1->id,
|
||||
$conversationid,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false
|
||||
);
|
||||
external_api::clean_returnvalue(core_message_external::get_conversation_returns(), $conv);
|
||||
|
||||
$conv = (array) $conv;
|
||||
$this->assertCount(3, $conv['messages']);
|
||||
$this->assertEquals($message3id, $conv['messages'][2]->id);
|
||||
$this->assertEquals($user1->id, $conv['messages'][2]->useridfrom);
|
||||
$this->assertEquals($message2id, $conv['messages'][1]->id);
|
||||
$this->assertEquals($user2->id, $conv['messages'][1]->useridfrom);
|
||||
$this->assertEquals($message1id, $conv['messages'][0]->id);
|
||||
$this->assertEquals($user1->id, $conv['messages'][0]->useridfrom);
|
||||
|
||||
// Test message offest and limit.
|
||||
$conv = core_message_external::get_conversation(
|
||||
$user1->id,
|
||||
$conversationid,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
true
|
||||
);
|
||||
external_api::clean_returnvalue(core_message_external::get_conversation_returns(), $conv);
|
||||
|
||||
$conv = (array) $conv;
|
||||
$this->assertCount(1, $conv['messages']);
|
||||
$this->assertEquals($message2id, $conv['messages'][0]->id);
|
||||
$this->assertEquals($user2->id, $conv['messages'][0]->useridfrom);
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2018111301.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2018111301.02; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user