diff --git a/mod/chat/classes/external.php b/mod/chat/classes/external.php index 887c7185ede..d993484ffd6 100644 --- a/mod/chat/classes/external.php +++ b/mod/chat/classes/external.php @@ -612,4 +612,135 @@ class mod_chat_external extends external_api { ) ); } + + /** + * Returns description of method parameters + * + * @return external_function_parameters + * @since Moodle 3.4 + */ + public static function get_sessions_parameters() { + return new external_function_parameters( + array( + 'chatid' => new external_value(PARAM_INT, 'Chat instance id.'), + 'groupid' => new external_value(PARAM_INT, 'Get messages from users in this group. + 0 means that the function will determine the user group', VALUE_DEFAULT, 0), + 'showall' => new external_value(PARAM_BOOL, 'Whether to show completed sessions or not.', VALUE_DEFAULT, false), + ) + ); + } + + /** + * Retrieves chat sessions for a given chat. + * + * @param int $chatid the chat instance id + * @param int $groupid filter messages by this group. 0 to determine the group. + * @param bool $showall whether to include incomplete sessions or not + * @return array of warnings and the sessions + * @since Moodle 3.4 + * @throws moodle_exception + */ + public static function get_sessions($chatid, $groupid = 0, $showall = false) { + global $DB; + + $params = self::validate_parameters(self::get_sessions_parameters(), + array( + 'chatid' => $chatid, + 'groupid' => $groupid, + 'showall' => $showall, + )); + $sessions = $warnings = array(); + + // Request and permission validation. + $chat = $DB->get_record('chat', array('id' => $params['chatid']), '*', MUST_EXIST); + list($course, $cm) = get_course_and_cm_from_instance($chat, 'chat'); + + $context = context_module::instance($cm->id); + self::validate_context($context); + + if (empty($chat->studentlogs) && !has_capability('mod/chat:readlog', $context)) { + throw new moodle_exception('nopermissiontoseethechatlog', 'chat'); + } + + if (!empty($params['groupid'])) { + $groupid = $params['groupid']; + // Determine is the group is visible to user. + if (!groups_group_visible($groupid, $course, $cm)) { + throw new moodle_exception('notingroup'); + } + } else { + // Check to see if groups are being used here. + if ($groupmode = groups_get_activity_groupmode($cm)) { + $groupid = groups_get_activity_group($cm); + // Determine is the group is visible to user (this is particullary for the group 0). + if (!groups_group_visible($groupid, $course, $cm)) { + throw new moodle_exception('notingroup'); + } + } else { + $groupid = 0; + } + } + + // If the user is allocated to a group, only show messages from people in the same group, or no group. + $queryparams = array('chatid' => $chat->id); + if ($groupid) { + $groupselect = " AND (groupid = :groupid OR groupid = 0)"; + $queryparams['groupid'] = $groupid; + } else { + $groupselect = ""; + } + + if ($messages = $DB->get_records_select('chat_messages', "chatid = :chatid $groupselect", $queryparams, "timestamp DESC")) { + $chatsessions = chat_get_sessions($messages, $params['showall']); + // Format sessions for external. + foreach ($chatsessions as $session) { + $sessionusers = array(); + foreach ($session->sessionusers as $sessionuser => $usermessagecount) { + $sessionusers[] = array( + 'userid' => $sessionuser, + 'messagecount' => $usermessagecount + ); + } + $session->sessionusers = $sessionusers; + $sessions[] = $session; + } + } + + $result = array(); + $result['sessions'] = $sessions; + $result['warnings'] = $warnings; + return $result; + } + + /** + * Returns description of method result value + * + * @return external_description + * @since Moodle 3.4 + */ + public static function get_sessions_returns() { + return new external_single_structure( + array( + 'sessions' => new external_multiple_structure( + new external_single_structure( + array( + 'sessionstart' => new external_value(PARAM_INT, 'Session start time.'), + 'sessionend' => new external_value(PARAM_INT, 'Session end time.'), + 'sessionusers' => new external_multiple_structure( + new external_single_structure( + array( + 'userid' => new external_value(PARAM_INT, 'User id.'), + 'messagecount' => new external_value(PARAM_INT, 'Number of messages in the session.'), + ) + ), 'Session users.' + ), + 'iscomplete' => new external_value(PARAM_BOOL, 'Whether the session is completed or not.'), + ) + ), + 'list of users' + ), + 'warnings' => new external_warnings() + ) + ); + } } diff --git a/mod/chat/db/services.php b/mod/chat/db/services.php index 2e0f946874d..dcc0897b8f5 100644 --- a/mod/chat/db/services.php +++ b/mod/chat/db/services.php @@ -81,5 +81,12 @@ $functions = array( 'type' => 'read', 'capabilities' => '', 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE) + ), + 'mod_chat_get_sessions' => array( + 'classname' => 'mod_chat_external', + 'methodname' => 'get_sessions', + 'description' => 'Retrieves chat sessions for a given chat.', + 'type' => 'read', + 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE) ) ); diff --git a/mod/chat/lib.php b/mod/chat/lib.php index 948fd3870b5..49c76f4745c 100644 --- a/mod/chat/lib.php +++ b/mod/chat/lib.php @@ -1485,7 +1485,7 @@ function mod_chat_core_calendar_provide_event_action(calendar_event $event, * Given a set of messages for a chat, return the completed chat sessions (including optionally not completed ones). * * @param array $messages list of messages from a chat - * @param bool $showall whether to include completed sessions or not + * @param bool $showall whether to include incomplete sessions or not * @return array the list of sessions * @since Moodle 3.4 */ diff --git a/mod/chat/tests/externallib_test.php b/mod/chat/tests/externallib_test.php index f17fb2e70a2..cf86bb896db 100644 --- a/mod/chat/tests/externallib_test.php +++ b/mod/chat/tests/externallib_test.php @@ -290,4 +290,145 @@ class mod_chat_external_testcase extends externallib_advanced_testcase { $this->assertCount(2, $chats['chats']); } + + /** + * Test get_sessions_empty_chat + */ + public function test_get_sessions_empty_chat() { + global $DB; + + $this->resetAfterTest(true); + + // Setup test data. + $this->setAdminUser(); + $course = $this->getDataGenerator()->create_course(); + $chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id)); + + $result = mod_chat_external::get_sessions($chat->id); + $result = external_api::clean_returnvalue(mod_chat_external::get_sessions_returns(), $result); + $this->assertEmpty($result['sessions']); + $this->assertEmpty($result['warnings']); + } + + + /** + * Test get_sessions_no_permissions_for_student + */ + public function test_get_sessions_no_permissions_for_student() { + global $DB; + + $this->resetAfterTest(true); + + // Setup test data. + $this->setAdminUser(); + $course = $this->getDataGenerator()->create_course(); + // Disable logs for students. + $chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id, 'studentlogs' => 0)); + // The admin has permissions to check logs. + $result = mod_chat_external::get_sessions($chat->id); + $result = external_api::clean_returnvalue(mod_chat_external::get_sessions_returns(), $result); + $this->assertEmpty($result['sessions']); + $this->assertEmpty($result['warnings']); + + $user = self::getDataGenerator()->create_user(); + $studentrole = $DB->get_record('role', array('shortname' => 'student')); + unassign_capability('mod/chat:readlog', $studentrole->id); + accesslib_clear_all_caches_for_unit_testing(); + + $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id); + $this->setUser($user); + // Students don't have permissions. + $this->expectException('moodle_exception'); + mod_chat_external::get_sessions($chat->id); + } + + /** + * Test get_sessions_not_completed_session + */ + public function test_get_sessions_not_completed_session() { + global $DB; + + $this->resetAfterTest(true); + + // Setup test data. + $this->setAdminUser(); + $course = $this->getDataGenerator()->create_course(); + $chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id)); + + $user = self::getDataGenerator()->create_user(); + $this->setUser($user); + $studentrole = $DB->get_record('role', array('shortname' => 'student')); + $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id); + + // Start a chat and send just one message. + $result = mod_chat_external::login_user($chat->id); + $result = external_api::clean_returnvalue(mod_chat_external::login_user_returns(), $result); + $chatsid = $result['chatsid']; + $result = mod_chat_external::send_chat_message($chatsid, 'hello!'); + $result = external_api::clean_returnvalue(mod_chat_external::send_chat_message_returns(), $result); + + // Check session is not marked as completed so it is not returned. + $result = mod_chat_external::get_sessions($chat->id); + $result = external_api::clean_returnvalue(mod_chat_external::get_sessions_returns(), $result); + $this->assertEmpty($result['sessions']); + $this->assertEmpty($result['warnings']); + + // Pass showall parameter to indicate that we want not completed sessions. + $result = mod_chat_external::get_sessions($chat->id, 0, true); + $result = external_api::clean_returnvalue(mod_chat_external::get_sessions_returns(), $result); + $this->assertCount(1, $result['sessions']); // One session. + $this->assertFalse($result['sessions'][0]['iscomplete']); // Session not complete. + $this->assertEmpty($result['warnings']); + } + + /** + * Test get_sessions_completed_session + */ + public function test_get_sessions_completed_session() { + global $DB; + + $this->resetAfterTest(true); + + // Setup test data. + $this->setAdminUser(); + $course = $this->getDataGenerator()->create_course(); + $chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id)); + + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $studentrole = $DB->get_record('role', array('shortname' => 'student')); + $this->getDataGenerator()->enrol_user($user1->id, $course->id, $studentrole->id); + $this->getDataGenerator()->enrol_user($user2->id, $course->id, $studentrole->id); + + // Start a chat and completeit. + $this->setUser($user1); + $result = mod_chat_external::login_user($chat->id); + $result = external_api::clean_returnvalue(mod_chat_external::login_user_returns(), $result); + $chatsid = $result['chatsid']; + $result = mod_chat_external::send_chat_message($chatsid, 'hello!'); + $result = external_api::clean_returnvalue(mod_chat_external::send_chat_message_returns(), $result); + $this->setUser($user2); + $result = mod_chat_external::login_user($chat->id); + $result = external_api::clean_returnvalue(mod_chat_external::login_user_returns(), $result); + $chatsid = $result['chatsid']; + $result = mod_chat_external::send_chat_message($chatsid, 'hello to you!'); + $result = external_api::clean_returnvalue(mod_chat_external::send_chat_message_returns(), $result); + // Need to change first messages and last message times to mark the session completed. + // We receive 4 messages (2 system messages that indicates user joined and the 2 messages sent by the users). + $messages = $DB->get_records('chat_messages', array('chatid' => $chat->id)); + // Messages just one hour ago and 70 seconds between them. + $timegap = 0; + $timenow = time(); + foreach ($messages as $message) { + $DB->set_field('chat_messages', 'timestamp', $timenow - HOURSECS + $timegap, array('id' => $message->id)); + $timegap += 70; + } + // Check session is completed. + $result = mod_chat_external::get_sessions($chat->id); + $result = external_api::clean_returnvalue(mod_chat_external::get_sessions_returns(), $result); + $this->assertCount(1, $result['sessions']); // One session. + $this->assertTrue($result['sessions'][0]['iscomplete']); // Session complete. + $this->assertEquals($timenow - HOURSECS + 70, $result['sessions'][0]['sessionstart']); // First not system message time. + $this->assertEmpty($result['warnings']); + } } diff --git a/mod/chat/version.php b/mod/chat/version.php index 587b96e4e16..0486c4031f7 100644 --- a/mod/chat/version.php +++ b/mod/chat/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2017111301; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2017111302; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2017110800; // Requires this Moodle version. $plugin->component = 'mod_chat'; // Full name of the plugin (used for diagnostics). $plugin->cron = 300;