first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
Official Chat Module for Moodle
------------------------------
The chat module now supports a backend daemon for
more efficiency.
It's still buggy and being worked on, but if you
want to test it and help out here are some quick
instructions:
1) Admin -> Config -> Modules -> Chat -> Settings
2) Set the method to "sockets" and set up the ports etc
3) Start the server like this (from the Unix command line):
cd moodle/mod/chat
php chatd.php --start &
4) Go to a chat room in Moodle and open it as normal.
------
KNOWN PROBLEMS
- User list is not always working
- Some browsers (eg Safari) cause lines to be repeated
by 10 - 20 times
- Occasionally "Document was empty" messages
Help solving these very welcome!
Martin, 31 July 2004
+138
View File
@@ -0,0 +1,138 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Provides support for the conversion of moodle1 backup to the moodle2 format
* Based off of a template @ http://docs.moodle.org/dev/Backup_1.9_conversion_for_developers
*
* @package mod_chat
* @copyright 2011 Aparup Banerjee <aparup@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Chat conversion handler
*/
class moodle1_mod_chat_handler extends moodle1_mod_handler {
/** @var moodle1_file_manager */
protected $fileman = null;
/** @var int cmid */
protected $moduleid = null;
/**
* Declare the paths in moodle.xml we are able to convert
*
* The method returns list of {@link convert_path} instances.
* For each path returned, the corresponding conversion method must be
* defined.
*
* Note that the path /MOODLE_BACKUP/COURSE/MODULES/MOD/CHAT does not
* actually exist in the file. The last element with the module name was
* appended by the moodle1_converter class.
*
* @return array of {@link convert_path} instances
*/
public function get_paths() {
return array(
new convert_path(
'chat', '/MOODLE_BACKUP/COURSE/MODULES/MOD/CHAT',
array(
'newfields' => array(
'introformat' => 0
)
)
)
);
}
/**
* This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/CHAT
* data available
*/
public function process_chat($data) {
global $CFG;
// Get the course module id and context id.
$instanceid = $data['id'];
$cminfo = $this->get_cminfo($instanceid);
$this->moduleid = $cminfo['id'];
$contextid = $this->converter->get_contextid(CONTEXT_MODULE, $this->moduleid);
// Replay the upgrade step 2010050101.
if ($CFG->texteditors !== 'textarea') {
$data['intro'] = text_to_html($data['intro'], false, false, true);
$data['introformat'] = FORMAT_HTML;
}
// Get a fresh new file manager for this instance.
$this->fileman = $this->converter->get_file_manager($contextid, 'mod_chat');
// Convert course files embedded into the intro.
$this->fileman->filearea = 'intro';
$this->fileman->itemid = 0;
$data['intro'] = moodle1_converter::migrate_referenced_files($data['intro'], $this->fileman);
// Start writing chat.xml.
$this->open_xml_writer("activities/chat_{$this->moduleid}/chat.xml");
$this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $this->moduleid,
'modulename' => 'chat', 'contextid' => $contextid));
$this->xmlwriter->begin_tag('chat', array('id' => $instanceid));
foreach ($data as $field => $value) {
if ($field <> 'id') {
$this->xmlwriter->full_tag($field, $value);
}
}
$this->xmlwriter->begin_tag('messages');
return $data;
}
/**
* This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/CHAT/MESSAGES/MESSAGE
* data available
*/
public function process_chat_message($data) {
// MDL-46466 - Should this be empty?
}
/**
* This is executed when we reach the closing </MOD> tag of our 'chat' path
*/
public function on_chat_end() {
// Close chat.xml.
$this->xmlwriter->end_tag('messages');
$this->xmlwriter->end_tag('chat');
$this->xmlwriter->end_tag('activity');
$this->close_xml_writer();
// Write inforef.xml.
$this->open_xml_writer("activities/chat_{$this->moduleid}/inforef.xml");
$this->xmlwriter->begin_tag('inforef');
$this->xmlwriter->begin_tag('fileref');
foreach ($this->fileman->get_fileids() as $fileid) {
$this->write_xml('file', array('id' => $fileid));
}
$this->xmlwriter->end_tag('fileref');
$this->xmlwriter->end_tag('inforef');
$this->close_xml_writer();
}
}
@@ -0,0 +1,69 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Defines backup_chat_activity_task class
*
* @package mod_chat
* @category backup
* @copyright 2010 onwards Dongsheng Cai <dongsheng@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/mod/chat/backup/moodle2/backup_chat_stepslib.php');
/**
* Provides the steps to perform one complete backup of the Chat instance
*/
class backup_chat_activity_task extends backup_activity_task {
/**
* No specific settings for this activity
*/
protected function define_my_settings() {
}
/**
* Defines a backup step to store the instance data in the chat.xml file
*/
protected function define_my_steps() {
$this->add_step(new backup_chat_activity_structure_step('chat_structure', 'chat.xml'));
}
/**
* Encodes URLs to the index.php and view.php scripts
*
* @param string $content some HTML text that eventually contains URLs to the activity instance scripts
* @return string the content with the URLs encoded
*/
public static function encode_content_links($content) {
global $CFG;
$base = preg_quote($CFG->wwwroot . '/mod/chat', '#');
// Link to the list of chats.
$pattern = "#(".$base."\/index.php\?id\=)([0-9]+)#";
$content = preg_replace($pattern, '$@CHATINDEX*$2@$', $content);
// Link to chat view by moduleid.
$pattern = "#(".$base."\/view.php\?id\=)([0-9]+)#";
$content = preg_replace($pattern, '$@CHATVIEWBYID*$2@$', $content);
return $content;
}
}
@@ -0,0 +1,67 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* @package mod_chat
* @subpackage backup-moodle2
* @copyright 2010 onwards Dongsheng Cai <dongsheng@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Define all the backup steps that will be used by the backup_chat_activity_task
*/
class backup_chat_activity_structure_step extends backup_activity_structure_step {
protected function define_structure() {
$userinfo = $this->get_setting_value('userinfo');
// Define each element separated.
$chat = new backup_nested_element('chat', array('id'), array(
'name', 'intro', 'introformat', 'keepdays', 'studentlogs',
'chattime', 'schedule', 'timemodified'));
$messages = new backup_nested_element('messages');
$message = new backup_nested_element('message', array('id'), array(
'userid', 'groupid', 'system', 'message_text', 'timestamp'));
// It is not cool to have two tags with same name, so we need to rename message field to message_text.
$message->set_source_alias('message', 'message_text');
// Renamed 'issystem' into 'system', for backward compatibility: 'system' is now a reserved word in MySQL 8.0.3+.
$message->set_source_alias('issystem', 'system');
// Build the tree.
$chat->add_child($messages);
$messages->add_child($message);
// Define sources.
$chat->set_source_table('chat', array('id' => backup::VAR_ACTIVITYID));
// User related messages only happen if we are including user info.
if ($userinfo) {
$message->set_source_table('chat_messages', array('chatid' => backup::VAR_PARENTID));
}
// Define id annotations.
$message->annotate_ids('user', 'userid');
$message->annotate_ids('group', 'groupid');
// Annotate the file areas in chat module.
$chat->annotate_files('mod_chat', 'intro', null); // The chat_intro area doesn't use itemid.
// Return the root element (chat), wrapped into standard activity structure.
return $this->prepare_activity_structure($chat);
}
}
@@ -0,0 +1,111 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* @package mod_chat
* @subpackage backup-moodle2
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/mod/chat/backup/moodle2/restore_chat_stepslib.php');
/**
* chat restore task that provides all the settings and steps to perform one
* complete restore of the activity
*/
class restore_chat_activity_task extends restore_activity_task {
/**
* Define (add) particular settings this activity can have
*/
protected function define_my_settings() {
// No particular settings for this activity.
}
/**
* Define (add) particular steps this activity can have
*/
protected function define_my_steps() {
// Chat only has one structure step.
$this->add_step(new restore_chat_activity_structure_step('chat_structure', 'chat.xml'));
}
/**
* Define the contents in the activity that must be
* processed by the link decoder
*/
public static function define_decode_contents() {
$contents = array();
$contents[] = new restore_decode_content('chat', array('intro'), 'chat');
$contents[] = new restore_decode_content('chat_messages', array('message'), 'chat_message');
return $contents;
}
/**
* Define the decoding rules for links belonging
* to the activity to be executed by the link decoder
*/
public static function define_decode_rules() {
$rules = array();
$rules[] = new restore_decode_rule('CHATVIEWBYID', '/mod/chat/view.php?id=$1', 'course_module');
$rules[] = new restore_decode_rule('CHATINDEX', '/mod/chat/index.php?id=$1', 'course');
return $rules;
}
/**
* Define the restore log rules that will be applied
* by the {@link restore_logs_processor} when restoring
* chat logs. It must return one array
* of {@link restore_log_rule} objects
*/
public static function define_restore_log_rules() {
$rules = array();
$rules[] = new restore_log_rule('chat', 'add', 'view.php?id={course_module}', '{chat}');
$rules[] = new restore_log_rule('chat', 'update', 'view.php?id={course_module}', '{chat}');
$rules[] = new restore_log_rule('chat', 'view', 'view.php?id={course_module}', '{chat}');
$rules[] = new restore_log_rule('chat', 'talk', 'view.php?id={course_module}', '{chat}');
$rules[] = new restore_log_rule('chat', 'report', 'report.php?id={course_module}', '{chat}');
return $rules;
}
/**
* Define the restore log rules that will be applied
* by the {@link restore_logs_processor} when restoring
* course logs. It must return one array
* of {@link restore_log_rule} objects
*
* Note this rules are applied when restoring course logs
* by the restore final task, but are defined here at
* activity level. All them are rules not linked to any module instance (cmid = 0)
*/
public static function define_restore_log_rules_for_course() {
$rules = array();
$rules[] = new restore_log_rule('chat', 'view all', 'index.php?id={course}', null);
return $rules;
}
}
@@ -0,0 +1,83 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* @package mod_chat
* @subpackage backup-moodle2
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Define all the restore steps that will be used by the restore_chat_activity_task
*/
/**
* Structure step to restore one chat activity
*/
class restore_chat_activity_structure_step extends restore_activity_structure_step {
protected function define_structure() {
$paths = array();
$userinfo = $this->get_setting_value('userinfo');
$paths[] = new restore_path_element('chat', '/activity/chat');
if ($userinfo) {
$paths[] = new restore_path_element('chat_message', '/activity/chat/messages/message');
}
// Return the paths wrapped into standard activity structure.
return $this->prepare_activity_structure($paths);
}
protected function process_chat($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->course = $this->get_courseid();
// Any changes to the list of dates that needs to be rolled should be same during course restore and course reset.
// See MDL-9367.
$data->chattime = $this->apply_date_offset($data->chattime);
// Insert the chat record.
$newitemid = $DB->insert_record('chat', $data);
// Immediately after inserting "activity" record, call this.
$this->apply_activity_instance($newitemid);
}
protected function process_chat_message($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->chatid = $this->get_new_parentid('chat');
$data->userid = $this->get_mappingid('user', $data->userid);
$data->groupid = $this->get_mappingid('group', $data->groupid);
$data->message = $data->message_text;
$data->issystem = $data->system;
$newitemid = $DB->insert_record('chat_messages', $data);
$this->set_mapping('chat_message', $oldid, $newitemid); // Because of decode.
}
protected function after_execute() {
// Add chat related files, no need to match by itemname (just internally handled context).
$this->add_related_files('mod_chat', 'intro', null);
}
}
BIN
View File
Binary file not shown.
+162
View File
@@ -0,0 +1,162 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
define('AJAX_SCRIPT', true);
require(__DIR__.'/../../config.php');
require_once(__DIR__ . '/lib.php');
$action = optional_param('action', '', PARAM_ALPHANUM);
$beepid = optional_param('beep', '', PARAM_RAW);
$chatsid = required_param('chat_sid', PARAM_ALPHANUM);
$theme = required_param('chat_theme', PARAM_ALPHANUMEXT);
$chatmessage = optional_param('chat_message', '', PARAM_RAW);
$chatlasttime = optional_param('chat_lasttime', 0, PARAM_INT);
$chatlastrow = optional_param('chat_lastrow', 1, PARAM_INT);
if (!confirm_sesskey()) {
throw new moodle_exception('invalidsesskey', 'error');
}
if (!$chatuser = $DB->get_record('chat_users', array('sid' => $chatsid))) {
throw new moodle_exception('notlogged', 'chat');
}
if (!$chat = $DB->get_record('chat', array('id' => $chatuser->chatid))) {
throw new moodle_exception('invaliduserid', 'error');
}
if (!$course = $DB->get_record('course', array('id' => $chat->course))) {
throw new moodle_exception('invalidcourseid', 'error');
}
if (!$cm = get_coursemodule_from_instance('chat', $chat->id, $course->id)) {
throw new moodle_exception('invalidcoursemodule', 'error');
}
if (!isloggedin()) {
throw new moodle_exception('notlogged', 'chat');
}
// Set up $PAGE so that format_text will work properly.
$PAGE->set_cm($cm, $course, $chat);
$PAGE->set_url('/mod/chat/chat_ajax.php', array('chat_sid' => $chatsid));
require_login($course, false, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/chat:chat', $context);
ob_start();
header('Expires: Sun, 28 Dec 1997 09:32:45 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
header('Content-Type: text/html; charset=utf-8');
switch ($action) {
case 'init':
$users = chat_get_users($chatuser->chatid, $chatuser->groupid, $cm->groupingid);
$users = chat_format_userlist($users, $course);
$response['users'] = $users;
echo json_encode($response);
break;
case 'chat':
\core\session\manager::write_close();
chat_delete_old_users();
$chatmessage = clean_text($chatmessage, FORMAT_MOODLE);
if (!empty($beepid)) {
$chatmessage = 'beep '.$beepid;
}
if (!empty($chatmessage)) {
chat_send_chatmessage($chatuser, $chatmessage, 0, $cm);
$chatuser->lastmessageping = time() - 2;
$DB->update_record('chat_users', $chatuser);
// Response OK message.
echo json_encode(true);
ob_end_flush();
}
break;
case 'update':
if ((time() - $chatlasttime) > $CFG->chat_old_ping) {
chat_delete_old_users();
}
if ($latestmessage = chat_get_latest_message($chatuser->chatid, $chatuser->groupid)) {
$chatnewlasttime = $latestmessage->timestamp;
} else {
$chatnewlasttime = 0;
}
if ($chatlasttime == 0) {
$chatlasttime = time() - $CFG->chat_old_ping;
}
$messages = chat_get_latest_messages($chatuser, $chatlasttime);
if (!empty($messages)) {
$num = count($messages);
} else {
$num = 0;
}
$chatnewrow = ($chatlastrow + $num) % 2;
$senduserlist = false;
if ($messages && ($chatlasttime != $chatnewlasttime)) {
foreach ($messages as $n => &$message) {
$tmp = new stdClass();
// When somebody enter room, user list will be updated.
if (!empty($message->issystem)) {
$senduserlist = true;
}
if ($html = chat_format_message_theme($message, $chatuser, $USER, $cm->groupingid, $theme)) {
$message->mymessage = ($USER->id == $message->userid);
$message->message = $html->html;
if (!empty($html->type)) {
$message->type = $html->type;
}
} else {
unset($messages[$n]);
}
}
}
if ($senduserlist) {
// Return users when system message arrives.
$users = chat_format_userlist(chat_get_users($chatuser->chatid, $chatuser->groupid, $cm->groupingid), $course);
$response['users'] = $users;
}
$DB->set_field('chat_users', 'lastping', time(), array('id' => $chatuser->id));
$response['lasttime'] = $chatnewlasttime;
$response['lastrow'] = $chatnewrow;
if ($messages) {
$response['msgs'] = $messages;
}
echo json_encode($response);
header('Content-Length: ' . ob_get_length());
ob_end_flush();
break;
default:
break;
}
+1093
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,111 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Activity base class.
*
* @package mod_chat
* @copyright 2017 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\analytics\indicator;
defined('MOODLE_INTERNAL') || die();
/**
* Activity base class.
*
* @package mod_chat
* @copyright 2017 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class activity_base extends \core_analytics\local\indicator\community_of_inquiry_activity {
/**
* feedback_viewed_events
*
* @return string[]
*/
protected function feedback_viewed_events() {
return array('\mod_chat\event\course_module_viewed', '\mod_chat\event\message_sent',
'\mod_chat\event\sessions_viewed');
}
/**
* feedback_replied_events
*
* @return string[]
*/
protected function feedback_replied_events() {
return array('\mod_chat\event\message_sent');
}
/**
* feedback_post_action
*
* @param \cm_info $cm
* @param int $contextid
* @param int $userid
* @param string[] $eventnames
* @param int $after
* @return bool
*/
protected function feedback_post_action(\cm_info $cm, $contextid, $userid, $eventnames, $after = false) {
if (empty($this->activitylogs[$contextid][$userid])) {
return false;
}
$logs = $this->activitylogs[$contextid][$userid];
if (empty($logs['\mod_chat\event\message_sent'])) {
// No feedback viewed if there is no submission.
return false;
}
// First user message time.
$firstmessage = $logs['\mod_chat\event\message_sent']->timecreated[0];
// We consider feedback another user messages.
foreach ($this->activitylogs[$contextid] as $anotheruserid => $logs) {
if ($anotheruserid == $userid) {
continue;
}
if (empty($logs['\mod_chat\event\message_sent'])) {
continue;
}
$firstmessagesenttime = $logs['\mod_chat\event\message_sent']->timecreated[0];
if (parent::feedback_post_action($cm, $contextid, $userid, $eventnames, $firstmessagesenttime)) {
return true;
}
// Continue with the next user.
}
return false;
}
/**
* feedback_check_grades
*
* @return bool
*/
protected function feedback_check_grades() {
// Chat's feedback is not contained in grades.
return false;
}
}
@@ -0,0 +1,56 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Cognitive depth indicator - chat.
*
* @package mod_chat
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\analytics\indicator;
defined('MOODLE_INTERNAL') || die();
/**
* Cognitive depth indicator - chat.
*
* @package mod_chat
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cognitive_depth extends activity_base {
/**
* Returns the name.
*
* If there is a corresponding '_help' string this will be shown as well.
*
* @return \lang_string
*/
public static function get_name(): \lang_string {
return new \lang_string('indicator:cognitivedepth', 'mod_chat');
}
public function get_indicator_type() {
return self::INDICATOR_COGNITIVE;
}
public function get_cognitive_depth_level(\cm_info $cm) {
return self::COGNITIVE_LEVEL_4;
}
}
@@ -0,0 +1,56 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Social breadth indicator - chat.
*
* @package mod_chat
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\analytics\indicator;
defined('MOODLE_INTERNAL') || die();
/**
* Social breadth indicator - chat.
*
* @package mod_chat
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class social_breadth extends activity_base {
/**
* Returns the name.
*
* If there is a corresponding '_help' string this will be shown as well.
*
* @return \lang_string
*/
public static function get_name(): \lang_string {
return new \lang_string('indicator:socialbreadth', 'mod_chat');
}
public function get_indicator_type() {
return self::INDICATOR_SOCIAL;
}
public function get_social_breadth_level(\cm_info $cm) {
return self::SOCIAL_LEVEL_2;
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Contains the class for fetching the important dates in mod_chat for a given module instance and a user.
*
* @package mod_chat
* @copyright 2021 Dongsheng Cai
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
declare(strict_types=1);
namespace mod_chat;
use core\activity_dates;
/**
* Class for fetching the important dates in mod_chat for a given module instance and a user.
*
*/
class dates extends activity_dates {
/**
* Returns a list of important dates in mod_chat.
*
* @return array
*/
protected function get_dates(): array {
$customdata = $this->cm->customdata;
$chat = (object) $customdata;
$chattime = $chat->chattime ?? 0;
$now = time();
if (!empty($chat->schedule) && $chattime > $now) {
return [
[
'dataid' => 'chattime',
'label' => get_string('nextchattime', 'mod_chat'),
'timestamp' => (int) $chattime
]
];
}
return [];
}
}
@@ -0,0 +1,38 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* The mod_chat instance list viewed event.
*
* @package mod_chat
* @copyright 2013 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_chat instance list viewed event class.
*
* @package mod_chat
* @since Moodle 2.7
* @copyright 2013 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed {
}
@@ -0,0 +1,47 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* The mod_chat course module viewed event.
*
* @package mod_chat
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_chat course module viewed event class.
*
* @package mod_chat
* @since Moodle 2.7
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class course_module_viewed extends \core\event\course_module_viewed {
protected function init() {
$this->data['crud'] = 'r';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'chat';
}
public static function get_objectid_mapping() {
return array('db' => 'chat', 'restore' => 'chat');
}
}
+93
View File
@@ -0,0 +1,93 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* The mod_chat message sent event.
*
* @package mod_chat
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_chat message sent event class.
*
* @package mod_chat
* @since Moodle 2.6
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class message_sent extends \core\event\base {
/**
* Returns description of what happened.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->relateduserid' has sent a message in the chat with course module id
'$this->contextinstanceid'.";
}
/**
* Return localised event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventmessagesent', 'mod_chat');
}
/**
* Get URL related to the action
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url('/mod/chat/view.php', array('id' => $this->contextinstanceid));
}
/**
* Init method.
*
* @return void
*/
protected function init() {
$this->data['crud'] = 'c';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'chat_messages';
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
if (!isset($this->relateduserid)) {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'chat_messages', 'restore' => 'chat_message');
}
}
+108
View File
@@ -0,0 +1,108 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* The mod_chat sessions viewed event.
*
* @package mod_chat
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_chat sessions viewed event class.
*
* @property-read array $other {
* Extra information about the event.
*
* - int start: start of period.
* - int end: end of period.
* }
*
* @package mod_chat
* @since Moodle 2.6
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class sessions_viewed extends \core\event\base {
/**
* Returns description of what happened.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' has viewed the sessions of the chat with course module id
'$this->contextinstanceid'.";
}
/**
* Return localised event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventsessionsviewed', 'mod_chat');
}
/**
* Get URL related to the action
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url('/mod/chat/report.php', array('id' => $this->contextinstanceid));
}
/**
* Init method.
*
* @return void
*/
protected function init() {
$this->data['crud'] = 'r';
$this->data['edulevel'] = self::LEVEL_OTHER;
$this->data['objecttable'] = 'chat';
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
if (!isset($this->other['start'])) {
throw new \coding_exception('The \'start\' value must be set in other.');
}
if (!isset($this->other['end'])) {
throw new \coding_exception('The \'end\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'chat', 'restore' => 'chat');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}
+833
View File
@@ -0,0 +1,833 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Chat external API
*
* @package mod_chat
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
defined('MOODLE_INTERNAL') || die;
require_once($CFG->dirroot . '/mod/chat/lib.php');
use core_course\external\helper_for_get_mods_by_courses;
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_multiple_structure;
use core_external\external_single_structure;
use core_external\external_value;
use core_external\external_warnings;
use core_external\util;
use mod_chat\external\chat_message_exporter;
/**
* Chat external functions
*
* @package mod_chat
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
class mod_chat_external extends external_api {
/**
* Returns description of method parameters
*
* @return external_function_parameters
* @since Moodle 3.0
*/
public static function login_user_parameters() {
return new external_function_parameters(
array(
'chatid' => new external_value(PARAM_INT, 'chat instance id'),
'groupid' => new external_value(PARAM_INT, 'group id, 0 means that the function will determine the user group',
VALUE_DEFAULT, 0),
)
);
}
/**
* Log the current user into a chat room in the given chat.
*
* @param int $chatid the chat instance id
* @param int $groupid the user group id
* @return array of warnings and the chat unique session id
* @since Moodle 3.0
* @throws moodle_exception
*/
public static function login_user($chatid, $groupid = 0) {
global $DB;
$params = self::validate_parameters(self::login_user_parameters(),
array(
'chatid' => $chatid,
'groupid' => $groupid
));
$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);
require_capability('mod/chat:chat', $context);
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;
}
}
// Get the unique chat session id.
// Since we are going to use the chat via Web Service requests we set the ajax version (since it's the most similar).
if (!$chatsid = chat_login_user($chat->id, 'ajax', $groupid, $course)) {
throw new moodle_exception('cantlogin', 'chat');
}
$result = array();
$result['chatsid'] = $chatsid;
$result['warnings'] = $warnings;
return $result;
}
/**
* Returns description of method result value
*
* @return \core_external\external_description
* @since Moodle 3.0
*/
public static function login_user_returns() {
return new external_single_structure(
array(
'chatsid' => new external_value(PARAM_ALPHANUM, 'unique chat session id'),
'warnings' => new external_warnings()
)
);
}
/**
* Returns description of method parameters
*
* @return external_function_parameters
* @since Moodle 3.0
*/
public static function get_chat_users_parameters() {
return new external_function_parameters(
array(
'chatsid' => new external_value(PARAM_ALPHANUM, 'chat session id (obtained via mod_chat_login_user)')
)
);
}
/**
* Get the list of users in the given chat session.
*
* @param int $chatsid the chat session id
* @return array of warnings and the user lists
* @since Moodle 3.0
* @throws moodle_exception
*/
public static function get_chat_users($chatsid) {
global $DB, $PAGE;
$params = self::validate_parameters(self::get_chat_users_parameters(),
array(
'chatsid' => $chatsid
));
$warnings = array();
// Request and permission validation.
if (!$chatuser = $DB->get_record('chat_users', array('sid' => $params['chatsid']))) {
throw new moodle_exception('notlogged', 'chat');
}
$chat = $DB->get_record('chat', array('id' => $chatuser->chatid), '*', MUST_EXIST);
list($course, $cm) = get_course_and_cm_from_instance($chat, 'chat');
$context = context_module::instance($cm->id);
self::validate_context($context);
require_capability('mod/chat:chat', $context);
// First, delete old users from the chats.
chat_delete_old_users();
$users = chat_get_users($chatuser->chatid, $chatuser->groupid, $cm->groupingid);
$returnedusers = array();
foreach ($users as $user) {
$userpicture = new user_picture($user);
$userpicture->size = 1; // Size f1.
$profileimageurl = $userpicture->get_url($PAGE)->out(false);
$returnedusers[] = array(
'id' => $user->id,
'fullname' => fullname($user),
'profileimageurl' => $profileimageurl
);
}
$result = array();
$result['users'] = $returnedusers;
$result['warnings'] = $warnings;
return $result;
}
/**
* Returns description of method result value
*
* @return \core_external\external_description
* @since Moodle 3.0
*/
public static function get_chat_users_returns() {
return new external_single_structure(
array(
'users' => new external_multiple_structure(
new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'user id'),
'fullname' => new external_value(PARAM_NOTAGS, 'user full name'),
'profileimageurl' => new external_value(PARAM_URL, 'user picture URL'),
)
),
'list of users'
),
'warnings' => new external_warnings()
)
);
}
/**
* Returns description of method parameters
*
* @return external_function_parameters
* @since Moodle 3.0
*/
public static function send_chat_message_parameters() {
return new external_function_parameters(
array(
'chatsid' => new external_value(PARAM_ALPHANUM, 'chat session id (obtained via mod_chat_login_user)'),
'messagetext' => new external_value(PARAM_RAW, 'the message text'),
'beepid' => new external_value(PARAM_RAW, 'the beep id', VALUE_DEFAULT, ''),
)
);
}
/**
* Send a message on the given chat session.
*
* @param int $chatsid the chat session id
* @param string $messagetext the message text
* @param string $beepid the beep message id
* @return array of warnings and the new message id (0 if the message was empty)
* @since Moodle 3.0
* @throws moodle_exception
*/
public static function send_chat_message($chatsid, $messagetext, $beepid = '') {
global $DB;
$params = self::validate_parameters(self::send_chat_message_parameters(),
array(
'chatsid' => $chatsid,
'messagetext' => $messagetext,
'beepid' => $beepid
));
$warnings = array();
// Request and permission validation.
if (!$chatuser = $DB->get_record('chat_users', array('sid' => $params['chatsid']))) {
throw new moodle_exception('notlogged', 'chat');
}
$chat = $DB->get_record('chat', array('id' => $chatuser->chatid), '*', MUST_EXIST);
list($course, $cm) = get_course_and_cm_from_instance($chat, 'chat');
$context = context_module::instance($cm->id);
self::validate_context($context);
require_capability('mod/chat:chat', $context);
$chatmessage = clean_text($params['messagetext'], FORMAT_MOODLE);
if (!empty($params['beepid'])) {
$chatmessage = 'beep ' . $params['beepid'];
}
if (!empty($chatmessage)) {
// Send the message.
$messageid = chat_send_chatmessage($chatuser, $chatmessage, 0, $cm);
// Update ping time.
$chatuser->lastmessageping = time() - 2;
$DB->update_record('chat_users', $chatuser);
} else {
$messageid = 0;
}
$result = array();
$result['messageid'] = $messageid;
$result['warnings'] = $warnings;
return $result;
}
/**
* Returns description of method result value
*
* @return \core_external\external_description
* @since Moodle 3.0
*/
public static function send_chat_message_returns() {
return new external_single_structure(
array(
'messageid' => new external_value(PARAM_INT, 'message sent id'),
'warnings' => new external_warnings()
)
);
}
/**
* Returns description of method parameters
*
* @return external_function_parameters
* @since Moodle 3.0
*/
public static function get_chat_latest_messages_parameters() {
return new external_function_parameters(
array(
'chatsid' => new external_value(PARAM_ALPHANUM, 'chat session id (obtained via mod_chat_login_user)'),
'chatlasttime' => new external_value(PARAM_INT, 'last time messages were retrieved (epoch time)', VALUE_DEFAULT, 0)
)
);
}
/**
* Get the latest messages from the given chat session.
*
* @param int $chatsid the chat session id
* @param int $chatlasttime last time messages were retrieved (epoch time)
* @return array of warnings and the new message id (0 if the message was empty)
* @since Moodle 3.0
* @throws moodle_exception
*/
public static function get_chat_latest_messages($chatsid, $chatlasttime = 0) {
global $DB, $CFG;
$params = self::validate_parameters(self::get_chat_latest_messages_parameters(),
array(
'chatsid' => $chatsid,
'chatlasttime' => $chatlasttime
));
$warnings = array();
// Request and permission validation.
if (!$chatuser = $DB->get_record('chat_users', array('sid' => $params['chatsid']))) {
throw new moodle_exception('notlogged', 'chat');
}
$chat = $DB->get_record('chat', array('id' => $chatuser->chatid), '*', MUST_EXIST);
list($course, $cm) = get_course_and_cm_from_instance($chat, 'chat');
$context = context_module::instance($cm->id);
self::validate_context($context);
require_capability('mod/chat:chat', $context);
$chatlasttime = $params['chatlasttime'];
if ((time() - $chatlasttime) > $CFG->chat_old_ping) {
chat_delete_old_users();
}
// Set default chat last time (to not retrieve all the conversations).
if ($chatlasttime == 0) {
$chatlasttime = time() - $CFG->chat_old_ping;
}
if ($latestmessage = chat_get_latest_message($chatuser->chatid, $chatuser->groupid)) {
$chatnewlasttime = $latestmessage->timestamp;
} else {
$chatnewlasttime = 0;
}
$messages = chat_get_latest_messages($chatuser, $chatlasttime);
$returnedmessages = array();
foreach ($messages as $message) {
// FORMAT_MOODLE is mandatory in the chat plugin.
[$messageformatted] = \core_external\util::format_text(
$message->message,
FORMAT_MOODLE,
$context->id,
'mod_chat',
'',
0
);
$returnedmessages[] = array(
'id' => $message->id,
'userid' => $message->userid,
'system' => (bool) $message->issystem,
'message' => $messageformatted,
'timestamp' => $message->timestamp,
);
}
// Update our status since we are active in the chat.
$DB->set_field('chat_users', 'lastping', time(), array('id' => $chatuser->id));
$result = array();
$result['messages'] = $returnedmessages;
$result['chatnewlasttime'] = $chatnewlasttime;
$result['warnings'] = $warnings;
return $result;
}
/**
* Returns description of method result value
*
* @return \core_external\external_description
* @since Moodle 3.0
*/
public static function get_chat_latest_messages_returns() {
return new external_single_structure(
array(
'messages' => new external_multiple_structure(
new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'message id'),
'userid' => new external_value(PARAM_INT, 'user id'),
'system' => new external_value(PARAM_BOOL, 'true if is a system message (like user joined)'),
'message' => new external_value(PARAM_RAW, 'message text'),
'timestamp' => new external_value(PARAM_INT, 'timestamp for the message'),
)
),
'list of users'
),
'chatnewlasttime' => new external_value(PARAM_INT, 'new last time'),
'warnings' => new external_warnings()
)
);
}
/**
* Returns description of method parameters
*
* @return external_function_parameters
* @since Moodle 3.0
*/
public static function view_chat_parameters() {
return new external_function_parameters(
array(
'chatid' => new external_value(PARAM_INT, 'chat instance id')
)
);
}
/**
* Trigger the course module viewed event and update the module completion status.
*
* @param int $chatid the chat instance id
* @return array of warnings and status result
* @since Moodle 3.0
* @throws moodle_exception
*/
public static function view_chat($chatid) {
global $DB, $CFG;
$params = self::validate_parameters(self::view_chat_parameters(),
array(
'chatid' => $chatid
));
$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);
require_capability('mod/chat:chat', $context);
// Call the url/lib API.
chat_view($chat, $course, $cm, $context);
$result = array();
$result['status'] = true;
$result['warnings'] = $warnings;
return $result;
}
/**
* Returns description of method result value
*
* @return \core_external\external_description
* @since Moodle 3.0
*/
public static function view_chat_returns() {
return new external_single_structure(
array(
'status' => new external_value(PARAM_BOOL, 'status: true if success'),
'warnings' => new external_warnings()
)
);
}
/**
* Describes the parameters for get_chats_by_courses.
*
* @return external_function_parameters
* @since Moodle 3.0
*/
public static function get_chats_by_courses_parameters() {
return new external_function_parameters (
array(
'courseids' => new external_multiple_structure(
new external_value(PARAM_INT, 'course id'), 'Array of course ids', VALUE_DEFAULT, array()
),
)
);
}
/**
* Returns a list of chats in a provided list of courses,
* if no list is provided all chats that the user can view will be returned.
*
* @param array $courseids the course ids
* @return array of chats details
* @since Moodle 3.0
*/
public static function get_chats_by_courses($courseids = array()) {
global $CFG;
$returnedchats = array();
$warnings = array();
$params = self::validate_parameters(self::get_chats_by_courses_parameters(), array('courseids' => $courseids));
$courses = array();
if (empty($params['courseids'])) {
$courses = enrol_get_my_courses();
$params['courseids'] = array_keys($courses);
}
// Ensure there are courseids to loop through.
if (!empty($params['courseids'])) {
list($courses, $warnings) = util::validate_courses($params['courseids'], $courses);
// Get the chats in this course, this function checks users visibility permissions.
// We can avoid then additional validate_context calls.
$chats = get_all_instances_in_courses("chat", $courses);
foreach ($chats as $chat) {
$chatcontext = context_module::instance($chat->coursemodule);
$chatdetails = helper_for_get_mods_by_courses::standard_coursemodule_element_values($chat, 'mod_chat');
if (has_capability('mod/chat:chat', $chatcontext)) {
$chatdetails['chatmethod'] = $CFG->chat_method;
$chatdetails['keepdays'] = $chat->keepdays;
$chatdetails['studentlogs'] = $chat->studentlogs;
$chatdetails['chattime'] = $chat->chattime;
$chatdetails['schedule'] = $chat->schedule;
}
if (has_capability('moodle/course:manageactivities', $chatcontext)) {
$chatdetails['timemodified'] = $chat->timemodified;
}
$returnedchats[] = $chatdetails;
}
}
$result = array();
$result['chats'] = $returnedchats;
$result['warnings'] = $warnings;
return $result;
}
/**
* Describes the get_chats_by_courses return value.
*
* @return external_single_structure
* @since Moodle 3.0
*/
public static function get_chats_by_courses_returns() {
return new external_single_structure(
array(
'chats' => new external_multiple_structure(
new external_single_structure(array_merge(
helper_for_get_mods_by_courses::standard_coursemodule_elements_returns(),
[
'chatmethod' => new external_value(PARAM_PLUGIN, 'chat method (sockets, ajax, header_js)',
VALUE_OPTIONAL),
'keepdays' => new external_value(PARAM_INT, 'keep days', VALUE_OPTIONAL),
'studentlogs' => new external_value(PARAM_INT, 'student logs visible to everyone', VALUE_OPTIONAL),
'chattime' => new external_value(PARAM_INT, 'chat time', VALUE_OPTIONAL),
'schedule' => new external_value(PARAM_INT, 'schedule type', VALUE_OPTIONAL),
'timemodified' => new external_value(PARAM_INT, 'time of last modification', VALUE_OPTIONAL),
]
), 'Chats')
),
'warnings' => new external_warnings(),
)
);
}
/**
* 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;
}
}
$messages = chat_get_session_messages($chat->id, $groupid, 0, 0, 'timestamp DESC');
if ($messages) {
$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 \core_external\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()
)
);
}
/**
* Returns description of method parameters
*
* @return external_function_parameters
* @since Moodle 3.4
*/
public static function get_session_messages_parameters() {
return new external_function_parameters(
array(
'chatid' => new external_value(PARAM_INT, 'Chat instance id.'),
'sessionstart' => new external_value(PARAM_INT, 'The session start time (timestamp).'),
'sessionend' => new external_value(PARAM_INT, 'The session end time (timestamp).'),
'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),
)
);
}
/**
* Retrieves messages of the given chat session.
*
* @param int $chatid the chat instance id
* @param int $sessionstart the session start time (timestamp)
* @param int $sessionend the session end time (timestamp)
* @param int $groupid filter messages by this group. 0 to determine the group.
* @return array of warnings and the messages
* @since Moodle 3.4
* @throws moodle_exception
*/
public static function get_session_messages($chatid, $sessionstart, $sessionend, $groupid = 0) {
global $DB, $PAGE;
$params = self::validate_parameters(self::get_session_messages_parameters(),
array(
'chatid' => $chatid,
'sessionstart' => $sessionstart,
'sessionend' => $sessionend,
'groupid' => $groupid,
));
$messages = $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;
}
}
$messages = chat_get_session_messages($chat->id, $groupid, $params['sessionstart'], $params['sessionend'],
'timestamp ASC');
if ($messages) {
foreach ($messages as $message) {
$exporter = new chat_message_exporter($message, array('context' => $context));
$returneditems[] = $exporter->export($PAGE->get_renderer('core'));
}
}
$result = array(
'messages' => $messages,
'warnings' => $warnings,
);
return $result;
}
/**
* Returns description of method result value
*
* @return \core_external\external_description
* @since Moodle 3.4
*/
public static function get_session_messages_returns() {
return new external_single_structure(
array(
'messages' => new external_multiple_structure(
chat_message_exporter::get_read_structure()
),
'warnings' => new external_warnings()
)
);
}
}
+101
View File
@@ -0,0 +1,101 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Class for exporting a chat message.
*
* @package mod_chat
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\external;
defined('MOODLE_INTERNAL') || die();
use core\external\exporter;
/**
* Class for exporting a chat message.
*
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class chat_message_exporter extends exporter {
/**
* Defines exporter properties.
*
* @return array
*/
protected static function define_properties() {
return array(
'id' => array(
'type' => PARAM_INT,
'description' => 'The message record id.',
),
'chatid' => array(
'type' => PARAM_INT,
'description' => 'The chat id.',
'default' => 0,
),
'userid' => array(
'type' => PARAM_INT,
'description' => 'The user who wrote the message.',
'default' => 0,
),
'groupid' => array(
'type' => PARAM_INT,
'description' => 'The group this message belongs to.',
'default' => 0,
),
'issystem' => array(
'type' => PARAM_BOOL,
'description' => 'Whether is a system message or not.',
'default' => false,
),
'message' => array(
'type' => PARAM_RAW,
'description' => 'The message text.',
),
'timestamp' => array(
'type' => PARAM_INT,
'description' => 'The message timestamp (indicates when the message was sent).',
'default' => 0,
),
);
}
/**
* Defines related information.
*
* @return array
*/
protected static function define_related() {
return array(
'context' => 'context',
);
}
/**
* Get the formatting parameters for the name.
*
* @return array
*/
protected function get_format_parameters_for_message() {
return [
'component' => 'mod_chat',
];
}
}
+121
View File
@@ -0,0 +1,121 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_chat\external;
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_single_structure;
use core_external\external_value;
use core_external\external_warnings;
/**
* External service to log viewed previous chat sessions.
*
* @package mod_chat
* @category external
* @copyright 2023 Rodrigo Mady <rodrigo.mady@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 4.3
*/
class view_sessions extends external_api {
/**
* Returns description of method parameters
*
* @return external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters([
'cmid' => new external_value(PARAM_INT, 'Course module id', VALUE_REQUIRED),
'start' => new external_value(PARAM_INT, 'Session start time', VALUE_DEFAULT, 0),
'end' => new external_value(PARAM_INT, 'Session end time', VALUE_DEFAULT, 0),
]);
}
/**
* Execute the chat view sessions event.
*
* @param int $cmid the chat course module id
* @param null|int $start
* @param null|int $end
* @return array
* @throws \restricted_context_exception
*/
public static function execute(int $cmid, ?int $start = 0, ?int $end = 0): array {
global $DB;
$warnings = [];
$status = false;
// Validate the cmid ID.
[
'cmid' => $cmid,
'start' => $start,
'end' => $end,
] = self::validate_parameters(self::execute_parameters(), [
'cmid' => $cmid,
'start' => $start,
'end' => $end,
]);
if (!$cm = get_coursemodule_from_id('chat', $cmid)) {
throw new \moodle_exception('invalidcoursemodule', 'error');
}
if (!$chat = $DB->get_record('chat', ['id' => $cm->instance])) {
throw new \moodle_exception('invalidcoursemodule', 'error');
}
$context = \context_module::instance($cm->id);
self::validate_context($context);
// Check capability.
if (has_capability('mod/chat:readlog', $context)) {
$params = [
'context' => $context,
'objectid' => $chat->id,
'other' => [
'start' => $start,
'end' => $end
]
];
$event = \mod_chat\event\sessions_viewed::create($params);
$status = true;
$event->add_record_snapshot('chat', $chat);
$event->trigger();
} else {
$warnings[] = [
'item' => $cm->id,
'warningcode' => 'nopermissiontoseethechatlog',
'message' => get_string('nopermissiontoseethechatlog', 'chat')
];
}
$result = [
'status' => $status,
'warnings' => $warnings
];
return $result;
}
/**
* Describe the return structure of the external service.
*
* @return external_single_structure
*/
public static function execute_returns(): external_single_structure {
return new external_single_structure([
'status' => new external_value(PARAM_BOOL, 'status: true if success'),
'warnings' => new external_warnings()
]);
}
}
+333
View File
@@ -0,0 +1,333 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Data provider.
*
* @package mod_chat
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\privacy;
defined('MOODLE_INTERNAL') || die();
use context;
use context_helper;
use context_module;
use moodle_recordset;
use stdClass;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\helper;
use core_privacy\local\request\transform;
use core_privacy\local\request\userlist;
use core_privacy\local\request\writer;
/**
* Data provider class.
*
* @package mod_chat
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\core_userlist_provider,
\core_privacy\local\request\plugin\provider {
/**
* Returns metadata.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection): collection {
$collection->add_database_table('chat_messages', [
'userid' => 'privacy:metadata:messages:userid',
'message' => 'privacy:metadata:messages:message',
'issystem' => 'privacy:metadata:messages:issystem',
'timestamp' => 'privacy:metadata:messages:timestamp',
], 'privacy:metadata:messages');
// The tables chat_messages_current and chat_users are not exported/deleted
// because they are considered as short-lived data and are deleted on a
// regular basis by cron, or during normal requests. TODO MDL-62006.
$collection->add_database_table('chat_messages_current', [
'userid' => 'privacy:metadata:messages:userid',
'message' => 'privacy:metadata:messages:message',
'issystem' => 'privacy:metadata:messages:issystem',
'timestamp' => 'privacy:metadata:messages:timestamp'
], 'privacy:metadata:chat_messages_current');
$collection->add_database_table('chat_users', [
'userid' => 'privacy:metadata:chat_users:userid',
'version' => 'privacy:metadata:chat_users:version',
'ip' => 'privacy:metadata:chat_users:ip',
'firstping' => 'privacy:metadata:chat_users:firstping',
'lastping' => 'privacy:metadata:chat_users:lastping',
'lastmessageping' => 'privacy:metadata:chat_users:lastmessageping',
'lang' => 'privacy:metadata:chat_users:lang'
], 'privacy:metadata:chat_users');
return $collection;
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid): \core_privacy\local\request\contextlist {
$contextlist = new \core_privacy\local\request\contextlist();
$sql = "
SELECT DISTINCT ctx.id
FROM {chat} c
JOIN {modules} m
ON m.name = :chat
JOIN {course_modules} cm
ON cm.instance = c.id
AND cm.module = m.id
JOIN {context} ctx
ON ctx.instanceid = cm.id
AND ctx.contextlevel = :modulelevel
JOIN {chat_messages} chm
ON chm.chatid = c.id
WHERE chm.userid = :userid";
$params = [
'chat' => 'chat',
'modulelevel' => CONTEXT_MODULE,
'userid' => $userid,
];
$contextlist->add_from_sql($sql, $params);
return $contextlist;
}
/**
* Get the list of users who have data within a context.
*
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
*/
public static function get_users_in_context(userlist $userlist) {
$context = $userlist->get_context();
if (!is_a($context, \context_module::class)) {
return;
}
$params = [
'instanceid' => $context->instanceid,
'modulename' => 'chat',
];
$sql = "SELECT chm.userid
FROM {course_modules} cm
JOIN {modules} m ON m.id = cm.module AND m.name = :modulename
JOIN {chat} c ON c.id = cm.instance
JOIN {chat_messages} chm ON chm.chatid = c.id
WHERE cm.id = :instanceid";
$userlist->add_from_sql('userid', $sql, $params);
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
global $DB;
$user = $contextlist->get_user();
$userid = $user->id;
$cmids = array_reduce($contextlist->get_contexts(), function($carry, $context) {
if ($context->contextlevel == CONTEXT_MODULE) {
$carry[] = $context->instanceid;
}
return $carry;
}, []);
if (empty($cmids)) {
return;
}
$chatidstocmids = static::get_chat_ids_to_cmids_from_cmids($cmids);
$chatids = array_keys($chatidstocmids);
// Export the messages.
list($insql, $inparams) = $DB->get_in_or_equal($chatids, SQL_PARAMS_NAMED);
$params = array_merge($inparams, ['userid' => $userid]);
$recordset = $DB->get_recordset_select('chat_messages', "chatid $insql AND userid = :userid", $params, 'timestamp, id');
static::recordset_loop_and_export($recordset, 'chatid', [], function($carry, $record) use ($user, $chatidstocmids) {
$message = $record->message;
if ($record->issystem) {
$message = get_string('message' . $record->message, 'mod_chat', fullname($user));
}
$carry[] = [
'message' => $message,
'sent_at' => transform::datetime($record->timestamp),
'is_system_generated' => transform::yesno($record->issystem),
];
return $carry;
}, function($chatid, $data) use ($user, $chatidstocmids) {
$context = context_module::instance($chatidstocmids[$chatid]);
$contextdata = helper::get_context_data($context, $user);
$finaldata = (object) array_merge((array) $contextdata, ['messages' => $data]);
helper::export_context_files($context, $user);
writer::with_context($context)->export_data([], $finaldata);
});
}
/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(context $context) {
global $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
return;
}
$cm = get_coursemodule_from_id('chat', $context->instanceid);
if (!$cm) {
return;
}
$chatid = $cm->instance;
$DB->delete_records_select('chat_messages', 'chatid = :chatid', ['chatid' => $chatid]);
$DB->delete_records_select('chat_messages_current', 'chatid = :chatid', ['chatid' => $chatid]);
$DB->delete_records_select('chat_users', 'chatid = :chatid', ['chatid' => $chatid]);
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
global $DB;
$userid = $contextlist->get_user()->id;
$cmids = array_reduce($contextlist->get_contexts(), function($carry, $context) {
if ($context->contextlevel == CONTEXT_MODULE) {
$carry[] = $context->instanceid;
}
return $carry;
}, []);
if (empty($cmids)) {
return;
}
$chatidstocmids = static::get_chat_ids_to_cmids_from_cmids($cmids);
$chatids = array_keys($chatidstocmids);
list($insql, $inparams) = $DB->get_in_or_equal($chatids, SQL_PARAMS_NAMED);
$sql = "chatid $insql AND userid = :userid";
$params = array_merge($inparams, ['userid' => $userid]);
$DB->delete_records_select('chat_messages', $sql, $params);
$DB->delete_records_select('chat_messages_current', $sql, $params);
$DB->delete_records_select('chat_users', $sql, $params);
}
/**
* Delete multiple users within a single context.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
*/
public static function delete_data_for_users(approved_userlist $userlist) {
global $DB;
$context = $userlist->get_context();
$cm = $DB->get_record('course_modules', ['id' => $context->instanceid]);
$chat = $DB->get_record('chat', ['id' => $cm->instance]);
list($userinsql, $userinparams) = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
$params = array_merge(['chatid' => $chat->id], $userinparams);
$sql = "chatid = :chatid AND userid {$userinsql}";
$DB->delete_records_select('chat_messages', $sql, $params);
$DB->delete_records_select('chat_messages_current', $sql, $params);
$DB->delete_records_select('chat_users', $sql, $params);
}
/**
* Return a dict of chat IDs mapped to their course module ID.
*
* @param array $cmids The course module IDs.
* @return array In the form of [$chatid => $cmid].
*/
protected static function get_chat_ids_to_cmids_from_cmids(array $cmids) {
global $DB;
list($insql, $inparams) = $DB->get_in_or_equal($cmids, SQL_PARAMS_NAMED);
$sql = "
SELECT c.id, cm.id AS cmid
FROM {chat} c
JOIN {modules} m
ON m.name = :chat
JOIN {course_modules} cm
ON cm.instance = c.id
AND cm.module = m.id
WHERE cm.id $insql";
$params = array_merge($inparams, ['chat' => 'chat']);
return $DB->get_records_sql_menu($sql, $params);
}
/**
* Loop and export from a recordset.
*
* @param moodle_recordset $recordset The recordset.
* @param string $splitkey The record key to determine when to export.
* @param mixed $initial The initial data to reduce from.
* @param callable $reducer The function to return the dataset, receives current dataset, and the current record.
* @param callable $export The function to export the dataset, receives the last value from $splitkey and the dataset.
* @return void
*/
protected static function recordset_loop_and_export(moodle_recordset $recordset, $splitkey, $initial,
callable $reducer, callable $export) {
$data = $initial;
$lastid = null;
foreach ($recordset as $record) {
if ($lastid && $record->{$splitkey} != $lastid) {
$export($lastid, $data);
$data = $initial;
}
$data = $reducer($data, $record);
$lastid = $record->{$splitkey};
}
$recordset->close();
if (!empty($lastid)) {
$export($lastid, $data);
}
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Search area for mod_chat activities.
*
* @package mod_chat
* @copyright 2015 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\search;
defined('MOODLE_INTERNAL') || die();
/**
* Search area for mod_chat activities.
*
* @package mod_chat
* @copyright 2015 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class activity extends \core_search\base_activity {
/**
* Returns true if this area uses file indexing.
*
* @return bool
*/
public function uses_file_indexing() {
return true;
}
}
+65
View File
@@ -0,0 +1,65 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* A scheduled task for chat cron.
*
* @package mod_chat
* @copyright 2019 Simey Lameze <simey@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\task;
defined('MOODLE_INTERNAL') || die();
/**
* The main schedule task for the chat module.
*
* @package mod_chat
* @copyright 2019 Simey Lameze <simey@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cron_task extends \core\task\scheduled_task {
/**
* Get a descriptive name for this task (shown to admins).
*
* @return string
*/
public function get_name() {
return get_string('crontask', 'mod_chat');
}
/**
* Run chat cron.
*/
public function execute() {
global $CFG, $DB;
require_once($CFG->dirroot . '/mod/chat/lib.php');
chat_update_chat_times();
chat_delete_old_users();
$timenow = time();
$subselect = "SELECT c.keepdays
FROM {chat} c
WHERE c.id = {chat_messages}.chatid";
$DB->delete_records_select('chat_messages', "($subselect) > 0 AND timestamp < (? - ($subselect) * ?)",
[$timenow, DAYSECS]);
$DB->delete_records_select('chat_messages_current', "timestamp < ?", [$timenow - 8 * HOURSECS]);
}
}
+114
View File
@@ -0,0 +1,114 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Plugin capabilities
*
* @package mod_chat
* @copyright 2006 Martin Dougiamas
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$capabilities = array(
'mod/chat:addinstance' => array(
'riskbitmask' => RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
'clonepermissionsfrom' => 'moodle/course:manageactivities'
),
'mod/chat:chat' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'student' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/chat:readlog' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'student' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/chat:deletelog' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/chat:exportparticipatedsession' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW,
// Not student - nervous about allowing this by default.
),
),
'mod/chat:exportsession' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW,
),
),
'mod/chat:view' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'user' => CAP_ALLOW,
'guest' => CAP_ALLOW
)
)
);
+34
View File
@@ -0,0 +1,34 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Event observers definition.
*
* @package mod_chat
* @category event
* @copyright 2010 Dongsheng Cai <dongsheng@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$observers = array(
// User logging out.
array(
'eventname' => '\core\event\user_loggedout',
'callback' => 'chat_user_logout',
'includefile' => '/mod/chat/lib.php'
)
);
+33
View File
@@ -0,0 +1,33 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Chat module installation.
*
* @package mod_chat
* @copyright 2024 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Perform the post-install procedures.
*/
function xmldb_chat_install() {
global $DB;
// Disable the chat activity module on new installs by default.
$DB->set_field('modules', 'visible', 0, ['name' => 'chat']);
}
+94
View File
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/chat/db" VERSION="20220530" COMMENT="XMLDB file for Moodle mod/chat"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="chat" COMMENT="Each of these is a chat room">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="intro" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="introformat" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="text format of intro field"/>
<FIELD NAME="keepdays" TYPE="int" LENGTH="11" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="studentlogs" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="chattime" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="schedule" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="course" UNIQUE="false" FIELDS="course"/>
</INDEXES>
</TABLE>
<TABLE NAME="chat_messages" COMMENT="Stores all the actual chat messages">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="chatid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="groupid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="issystem" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="message" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="timestamp" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="chatid" TYPE="foreign" FIELDS="chatid" REFTABLE="chat" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
<INDEX NAME="groupid" UNIQUE="false" FIELDS="groupid"/>
<INDEX NAME="timestamp-chatid" UNIQUE="false" FIELDS="timestamp, chatid"/>
</INDEXES>
</TABLE>
<TABLE NAME="chat_messages_current" COMMENT="Stores current session">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="chatid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="groupid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="issystem" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="message" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="timestamp" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="chatid" TYPE="foreign" FIELDS="chatid" REFTABLE="chat" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
<INDEX NAME="groupid" UNIQUE="false" FIELDS="groupid"/>
<INDEX NAME="timestamp-chatid" UNIQUE="false" FIELDS="timestamp, chatid"/>
</INDEXES>
</TABLE>
<TABLE NAME="chat_users" COMMENT="Keeps track of which users are in which chat rooms">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="chatid" TYPE="int" LENGTH="11" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="userid" TYPE="int" LENGTH="11" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="groupid" TYPE="int" LENGTH="11" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="version" TYPE="char" LENGTH="16" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="ip" TYPE="char" LENGTH="45" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="firstping" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="lastping" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="lastmessageping" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="sid" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="lang" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="chatid" TYPE="foreign" FIELDS="chatid" REFTABLE="chat" REFFIELDS="id"/>
<KEY NAME="course" TYPE="foreign" FIELDS="course" REFTABLE="course" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
<INDEX NAME="lastping" UNIQUE="false" FIELDS="lastping"/>
<INDEX NAME="groupid" UNIQUE="false" FIELDS="groupid"/>
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>
+34
View File
@@ -0,0 +1,34 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Definition of log events
*
* @package mod_chat
* @category log
* @copyright 2010 Petr Skoda (http://skodak.org)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$logs = array(
array('module' => 'chat', 'action' => 'view', 'mtable' => 'chat', 'field' => 'name'),
array('module' => 'chat', 'action' => 'add', 'mtable' => 'chat', 'field' => 'name'),
array('module' => 'chat', 'action' => 'update', 'mtable' => 'chat', 'field' => 'name'),
array('module' => 'chat', 'action' => 'report', 'mtable' => 'chat', 'field' => 'name'),
array('module' => 'chat', 'action' => 'talk', 'mtable' => 'chat', 'field' => 'name'),
);
+108
View File
@@ -0,0 +1,108 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Chat external functions and service definitions.
*
* @package mod_chat
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
defined('MOODLE_INTERNAL') || die;
$functions = array(
'mod_chat_login_user' => array(
'classname' => 'mod_chat_external',
'methodname' => 'login_user',
'description' => 'Log a user into a chat room in the given chat.',
'type' => 'write',
'capabilities' => 'mod/chat:chat',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_chat_get_chat_users' => array(
'classname' => 'mod_chat_external',
'methodname' => 'get_chat_users',
'description' => 'Get the list of users in the given chat session.',
'type' => 'read',
'capabilities' => 'mod/chat:chat',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_chat_send_chat_message' => array(
'classname' => 'mod_chat_external',
'methodname' => 'send_chat_message',
'description' => 'Send a message on the given chat session.',
'type' => 'write',
'capabilities' => 'mod/chat:chat',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_chat_get_chat_latest_messages' => array(
'classname' => 'mod_chat_external',
'methodname' => 'get_chat_latest_messages',
'description' => 'Get the latest messages from the given chat session.',
'type' => 'read',
'capabilities' => 'mod/chat:chat',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_chat_view_chat' => array(
'classname' => 'mod_chat_external',
'methodname' => 'view_chat',
'description' => 'Trigger the course module viewed event and update the module completion status.',
'type' => 'write',
'capabilities' => 'mod/chat:chat',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_chat_get_chats_by_courses' => array(
'classname' => 'mod_chat_external',
'methodname' => 'get_chats_by_courses',
'description' => 'Returns a list of chat instances in a provided set of courses,
if no courses are provided then all the chat instances the user has access to will be returned.',
'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)
),
'mod_chat_get_session_messages' => array(
'classname' => 'mod_chat_external',
'methodname' => 'get_session_messages',
'description' => 'Retrieves messages of the given chat session.',
'type' => 'read',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_chat_view_sessions' => [
'classname' => 'mod_chat\external\view_sessions',
'methodname' => 'execute',
'description' => 'Trigger the chat session viewed event.',
'type' => 'write',
'capabilities' => 'mod/chat:readlog',
'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE]
],
);
+36
View File
@@ -0,0 +1,36 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Definition of chat scheduled tasks.
*
* @package mod_chat
* @copyright 2019 Simey Lameze <simey@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$tasks = array(
array(
'classname' => '\mod_chat\task\cron_task',
'blocking' => 0,
'minute' => '*/5',
'hour' => '*',
'day' => '*',
'month' => '*',
'dayofweek' => '*'
)
);
+39
View File
@@ -0,0 +1,39 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Upgrade code for the chat activity
*
* @package mod_chat
* @copyright 2006 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
function xmldb_chat_upgrade($oldversion) {
// Automatically generated Moodle v4.1.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.2.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.3.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+9
View File
@@ -0,0 +1,9 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>
</title>
</head>
<body bgcolor="#FFFFFF">
</body>
</html>
+114
View File
@@ -0,0 +1,114 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
require_once('../../../config.php');
require_once('../lib.php');
$id = required_param('id', PARAM_INT);
$groupid = optional_param('groupid', 0, PARAM_INT); // Only for teachers.
$theme = optional_param('chat_theme', 'course_theme', PARAM_SAFEDIR); // The value course_theme == the current theme.
$url = new moodle_url('/mod/chat/gui_ajax/index.php', array('id' => $id));
if ($groupid !== 0) {
$url->param('groupid', $groupid);
}
$PAGE->set_url($url);
$PAGE->set_popup_notification_allowed(false); // No popup notifications in the chat window.
$PAGE->requires->strings_for_js(array('coursetheme', 'bubble', 'compact'), 'mod_chat');
$chat = $DB->get_record('chat', array('id' => $id), '*', MUST_EXIST);
$course = $DB->get_record('course', array('id' => $chat->course), '*', MUST_EXIST);
$cm = get_coursemodule_from_instance('chat', $chat->id, $course->id, false, MUST_EXIST);
$context = context_module::instance($cm->id);
require_login($course, false, $cm);
require_capability('mod/chat:chat', $context);
// Check to see if groups are being used here.
if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used.
if ($groupid = groups_get_activity_group($cm)) {
if (!$group = groups_get_group($groupid)) {
throw new \moodle_exception('invalidgroupid');
}
$groupname = ': '.$group->name;
} else {
$groupname = ': '.get_string('allparticipants');
}
} else {
$groupid = 0;
$groupname = '';
}
// If requested theme doesn't exist, use default 'bubble' theme.
if ($theme != 'course_theme' and !file_exists(__DIR__ . '/theme/'.$theme.'/chat.css')) {
$theme = 'compact';
}
// Log into the chat room.
if (!$chatsid = chat_login_user($chat->id, 'ajax', $groupid, $course)) {
throw new \moodle_exception('cantlogin', 'chat');
}
$courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
$module = array(
'name' => 'mod_chat_ajax', // Chat gui's are not real plugins, we have to break the naming standards for JS modules here.
'fullpath' => '/mod/chat/gui_ajax/module.js',
'requires' => array('base', 'dom', 'event', 'event-mouseenter', 'event-key', 'json-parse', 'io', 'overlay', 'yui2-resize',
'yui2-layout', 'yui2-menu'),
'strings' => array(array('send', 'chat'), array('sending', 'chat'), array('inputarea', 'chat'), array('userlist', 'chat'),
array('modulename', 'chat'), array('beep', 'chat'), array('talk', 'chat'))
);
$modulecfg = array(
'home' => $CFG->wwwroot.'/mod/chat/view.php?id='.$cm->id,
'chaturl' => $CFG->wwwroot.'/mod/chat/gui_ajax/index.php?id='.$id,
'theme' => $theme,
'userid' => $USER->id,
'sid' => $chatsid,
'timer' => 3000,
'chat_lasttime' => 0,
'chat_lastrow' => null,
'chatroom_name' => $courseshortname . ": " . format_string($chat->name, true) . $groupname
);
$PAGE->requires->js_init_call('M.mod_chat_ajax.init', array($modulecfg), false, $module);
$PAGE->set_title(get_string('modulename', 'chat').": $courseshortname: ".format_string($chat->name, true)."$groupname");
$PAGE->add_body_class('yui-skin-sam');
$PAGE->activityheader->disable();
$PAGE->set_pagelayout('embedded');
if ( $theme != 'course_theme') {
$PAGE->requires->css('/mod/chat/gui_ajax/theme/'.$theme.'/chat.css');
}
echo $OUTPUT->header();
echo $OUTPUT->box(html_writer::tag('h2', get_string('participants'), array('class' => 'accesshide')) .
'<ul id="users-list" class="list-group"></ul>', '', 'chat-userlist');
echo $OUTPUT->box('', '', 'chat-options');
echo $OUTPUT->box(html_writer::tag('h2', get_string('messages', 'chat'), array('class' => 'accesshide')) .
'<ul id="messages-list"></ul>', '', 'chat-messages');
$table = new html_table();
$table->data = [[
'<div class="d-flex flex-wrap align-items-center"><div class="d-flex"><label class="accesshide" for="input-message">'.
get_string('entermessage', 'chat').' </label>'.
'<span class="mb-3"><input type="text" disabled="true" class="form-control" ' .
'id="input-message" value="Loading..." size="48" /></span>'.
'<span class="mb-3"><input type="button" id="button-send" class="btn btn-secondary mx-1" ' .
'value="'.get_string('send', 'chat').'" />' .$OUTPUT->help_icon('usingchat', 'chat'). '</span></div>' .
' <div class="mb-3 d-flex ml-auto"><a id="choosetheme" href="###">'.
get_string('themes').
' &raquo; </a></div></div>',
]];
echo $OUTPUT->box(html_writer::tag('h2', get_string('composemessage', 'chat'), array('class' => 'accesshide')) .
html_writer::table($table), '', 'chat-input-area');
echo $OUTPUT->box('', '', 'chat-notify');
echo $OUTPUT->footer();
+265
View File
@@ -0,0 +1,265 @@
/*
* NOTE: the /mod/chat/gui_header_js/ is not a real plugin,
* ideally this code should be in /mod/chat/module.js
*/
/**
* @namespace M.mod_chat_ajax
*/
M.mod_chat_ajax = M.mod_chat_ajax || {};
/**
* Init ajax based Chat UI.
* @namespace M.mod_chat_ajax
* @function
* @param {YUI} Y
* @param {Object} cfg configuration data
*/
M.mod_chat_ajax.init = function(Y, cfg) {
var gui_ajax = {
// Properties.
api : M.cfg.wwwroot + '/mod/chat/chat_ajax.php?sesskey=' + M.cfg.sesskey, // The path to the ajax callback script.
cfg : {}, // A configuration variable.
interval : null, // The interval object for refreshes.
layout : null, // A reference to the layout used in this module.
messages : [], // An array of messages.
scrollable : true, // True is scrolling should occur.
thememenu : null, // A reference to the menu for changing themes.
// Elements
messageinput : null,
sendbutton : null,
messagebox : null,
init : function(cfg) {
this.cfg = cfg;
this.cfg.req_count = this.cfg.req_count || 0;
participantswidth = 180;
if (Y.one('#input-message').get('docWidth') < 640) {
participantswidth = 120;
}
this.layout = new Y.YUI2.widget.Layout({
units : [
{position: 'right', width: participantswidth, resize: true, gutter: '1px', scroll: true, body: 'chat-userlist', animate: false},
{position: 'bottom', height: 42, resize: false, body: 'chat-input-area', gutter: '1px', collapse: false, resize: false},
{position: 'center', body: 'chat-messages', gutter: '0px', scroll: true}
]
});
this.layout.on('render', function() {
var unit = this.getUnitByPosition('right');
if (unit) {
unit.on('close', function() {
closeLeft();
});
}
}, this.layout);
this.layout.render();
// Gather the general elements.
this.messageinput = Y.one('#input-message');
this.sendbutton = Y.one('#button-send');
this.messagebox = Y.one('#chat-messages');
// Set aria attributes to messagebox and chat-userlist.
this.messagebox.set('role', 'log');
this.messagebox.set('aria-live', 'polite');
var userlist = Y.one('#chat-userlist');
userlist.set('aria-live', 'polite');
userlist.set('aria-relevant', 'all');
// Attach the default events for this module.
this.sendbutton.on('click', this.send, this);
this.messagebox.on('mouseenter', function() {
this.scrollable = false;
}, this);
this.messagebox.on('mouseleave', function() {
this.scrollable = true;
}, this);
// Send the message when the enter key is pressed.
Y.on('key', this.send, this.messageinput, 'press:13', this);
document.title = this.cfg.chatroom_name;
// Prepare and execute the first AJAX request of information.
Y.io(this.api,{
method : 'POST',
data : build_querystring({
action : 'init',
chat_init : 1,
chat_sid : this.cfg.sid,
chat_theme : this.cfg.theme
}),
on : {
success : function(tid, outcome) {
this.messageinput.removeAttribute('disabled');
this.messageinput.set('value', '');
this.messageinput.focus();
try {
var data = Y.JSON.parse(outcome.responseText);
} catch (ex) {
return;
}
this.update_users(data.users);
}
},
context : this
});
var scope = this;
this.interval = setInterval(function() {
scope.update_messages();
}, this.cfg.timer, this);
// Create and initalise theme changing menu.
this.thememenu = new Y.YUI2.widget.Menu('basicmenu', {xy:[0,0]});
this.thememenu.addItems([
{text: M.util.get_string('bubble', 'mod_chat'), url: this.cfg.chaturl + '&chat_theme=bubble'},
{text: M.util.get_string('compact', 'mod_chat'), url: this.cfg.chaturl + '&chat_theme=compact'},
{text: M.util.get_string('coursetheme', 'mod_chat'), url: this.cfg.chaturl + '&chat_theme=course_theme'}
]);
this.thememenu.render(document.body);
Y.one('#choosetheme').on('click', function(e) {
this.moveTo((e.pageX - 20), (e.pageY - 20));
this.show();
}, this.thememenu);
// Set the data-placement for the help-icon to display all the content.
this.helpicon = Y.one('#button-send + a');
this.dataset = this.helpicon.get('dataset');
this.dataset.placement = 'top';
this.helpicon.set('dataset', this.dataset);
},
append_message : function(key, message, row) {
var item = Y.Node.create('<li id="mdl-chat-entry-' + key + '">' + message.message + '</li>');
item.addClass((message.mymessage) ? 'mdl-chat-my-entry' : 'mdl-chat-entry');
Y.one('#messages-list').append(item);
if (message.type && message.type == 'beep') {
var audioElement = document.createElement('audio');
audioElement.setAttribute('src', '../beep.mp3');
audioElement.play();
}
},
send : function(e, beep) {
if((this.messageinput.get('value') != '') || (typeof beep != 'undefined')) {
this.sendbutton.set('value', M.util.get_string('sending', 'chat'));
var data = {
chat_message : (!beep) ? this.messageinput.get('value') : '',
chat_sid : this.cfg.sid,
chat_theme : this.cfg.theme
};
if (beep) {
data.beep = beep
}
data.action = 'chat';
Y.io(this.api, {
method : 'POST',
data : build_querystring(data),
on : {
success : this.send_callback
},
context : this
});
}
},
send_callback : function(tid, outcome, args) {
try {
var data = Y.JSON.parse(outcome.responseText);
} catch (ex) {
return;
}
this.sendbutton.set('value', M.util.get_string('send', 'chat'));
this.messageinput.set('value', '');
clearInterval(this.interval);
this.update_messages();
var scope = this;
this.interval = setInterval(function() {
scope.update_messages();
}, this.cfg.timer, this);
},
talkto: function (e, name) {
this.messageinput.set('value', "To " + name + ": ");
this.messageinput.focus();
},
update_messages : function() {
this.cfg.req_count++;
Y.io(this.api, {
method : 'POST',
data : build_querystring({
action: 'update',
chat_lastrow : this.cfg.chat_lastrow || false,
chat_lasttime : this.cfg.chat_lasttime,
chat_sid : this.cfg.sid,
chat_theme : this.cfg.theme
}),
on : {
success : this.update_messages_callback
},
context : this
});
},
update_messages_callback : function(tid, outcome) {
try {
var data = Y.JSON.parse(outcome.responseText);
} catch (ex) {
return;
}
if (data.error) {
clearInterval(this.interval);
alert(data.error);
window.location = this.cfg.home;
}
this.cfg.chat_lasttime = data.lasttime;
this.cfg.chat_lastrow = data.lastrow;
// Update messages.
for (var key in data.msgs){
if (!M.util.in_array(key, this.messages)) {
this.messages.push(key);
this.append_message(key, data.msgs[key], data.lastrow);
}
}
// Update users.
this.update_users(data.users);
// Scroll to the bottom of the message list
if (this.scrollable) {
Y.Node.getDOMNode(this.messagebox).parentNode.scrollTop += 500;
}
this.messageinput.focus();
},
update_users : function(users) {
if (!users) {
return;
}
var list = Y.one('#users-list');
list.get('children').remove();
for (var i in users) {
var li = Y.Node.create('<li><table><tr><td>' + users[i].picture + '</td><td></td></tr></table></li>');
if (users[i].id == this.cfg.userid) {
li.all('td').item(1).append(Y.Node.create('<strong><a target="_blank" href="' + users[i].url + '">' + users[i].name + '</a></strong>'));
} else {
li.all('td').item(1).append(Y.Node.create('<div><a target="_blank" href="' + users[i].url + '">' + users[i].name + '</a></div>'));
var talk = Y.Node.create('<a href="###">' + M.util.get_string('talk', 'chat') + '</a>');
talk.on('click', this.talkto, this, users[i].name);
var beep = Y.Node.create('<a href="###">' + M.util.get_string('beep', 'chat') + '</a>');
beep.on('click', this.send, this, users[i].id);
li.all('td').item(1).append(Y.Node.create('<div></div>').append(talk).append('&nbsp;').append(beep));
}
list.append(li);
}
}
};
gui_ajax.init(cfg);
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

+249
View File
@@ -0,0 +1,249 @@
.yui-skin-sam .yui-layout .yui-layout-hd {
border: 0;
}
.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd-nohd {
border: 0;
}
.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd {
border: 0;
}
.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-unit-right {
background: white;
}
.yui-skin-sam .yui-layout-unit-bottom {
background: #f2f2f2;
}
.yui-skin-sam .yui-layout-unit-right {
background: #eef2f8;
}
.yui-skin-sam .yui-layout-unit-center {
background: white;
}
.yui-skin-sam .yui-layout-unit-top {
background: #ffe39d;
}
.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd {
background: transparent;
}
#chat-messages {
padding-top: 15px;
}
#input-message {
background: #fff url(input.png) repeat-x scroll 0 0;
padding: 0 9px;
border: 1px solid #999;
border-radius: 9px;
-moz-border-radius: 9px;
}
.mdl-chat-entry,
.mdl-chat-my-entry {
clear: both;
}
.mdl-chat-entry .chat-event {
padding-bottom: 15px;
}
.chat-message .chat-message-meta {
padding-top: 15px;
padding-bottom: 15px;
}
.chat-message .chat-message-meta .user {
white-space: nowrap;
}
.chat-message .picture {
vertical-align: middle;
}
.chat-message .right {
text-align: right;
}
.chat-message .left {
text-align: left;
}
/*rtl:ignore*/
.chat-message .right,
.chat-message .left {
direction: ltr;
}
#chat-input-area,
#chat-input-area table.generaltable,
#chat-input-area table.generaltable td.cell {
background: #92b3e8;
border: 0;
height: 100%;
}
#chat-userlist {
background: #e3e8f0;
height: 100%;
}
/**
* The following CSS is a cut down version of PURE CSS SPEECH BUBBLES.
* Moodle only uses a small subset of the original.
* The original version is available at http://nicolasgallagher.com/pure-css-speech-bubbles/
*/
/* ------------------------------------------
PURE CSS SPEECH BUBBLES
by Nicolas Gallagher
- http://nicolasgallagher.com/pure-css-speech-bubbles/
http://nicolasgallagher.com
http://twitter.com/necolas
Created: 02 March 2010
Version: 1.2 (03 March 2011)
Dual licensed under MIT and GNU GPLv2 © Nicolas Gallagher
------------------------------------------ */
.triangle-border {
position: relative;
padding: 10px;
margin: 1em 0 3em;
border: 2px solid #5a8f00;
color: #333;
background: #fff;
/* css3 */
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
/* moodle specific */
margin-top: 0;
/* end moodle specific */
}
/* moodle specific */
@media all and (max-device-width: 320px) {
.triangle-border {
width: 50%;
}
}
@media all and (min-device-width: 321px) and (max-device-width: 640px) {
.triangle-border {
width: 60%;
}
}
@media all and (min-device-width: 641px) {
.triangle-border {
width: 65%;
}
}
/* end moodle specific */
/* Variant : for left positioned triangle
------------------------------------------ */
.triangle-border.left {
margin-left: 30px;
/* moodle specific */
float: right;
/* end moodle specific */
}
/* Variant : for right positioned triangle
------------------------------------------ */
.triangle-border.right {
margin-right: 30px;
/* moodle specific */
float: left;
/* end moodle specific */
}
.triangle-border:before {
content: "";
position: absolute;
bottom: -20px; /* value = - border-top-width - border-bottom-width */
left: 40px; /* controls horizontal position */
border-width: 20px 20px 0;
border-style: solid;
border-color: #5a8f00 transparent;
/* reduce the damage in FF3.0 */
display: block;
width: 0;
}
/* creates the smaller triangle */
.triangle-border:after {
content: "";
position: absolute;
bottom: -13px; /* value = - border-top-width - border-bottom-width */
left: 47px; /* value = (:before left) + (:before border-left) - (:after border-left) */
border-width: 13px 13px 0;
border-style: solid;
border-color: #fff transparent;
/* reduce the damage in FF3.0 */
display: block;
width: 0;
}
/* Variant : left
------------------------------------------ */
/* creates the larger triangle */
.triangle-border.left:before {
top: 7px; /* controls vertical position */
bottom: auto;
left: -24px; /* value = - border-left-width - border-right-width */
border-width: 10px 24px 10px 0;
border-color: transparent #5a8f00;
}
/* creates the smaller triangle */
.triangle-border.left:after {
top: 8px; /* value = (:before top) + (:before border-top) - (:after border-top) */
bottom: auto;
left: -21px; /* value = - border-left-width - border-right-width */
border-width: 9px 21px 9px 0;
border-color: transparent #fff;
}
/* Variant : right
------------------------------------------ */
/* creates the larger triangle */
.triangle-border.right:before {
top: 7px; /* controls vertical position */
bottom: auto;
left: auto;
right: -24px; /* value = - border-left-width - border-right-width */
border-width: 10px 0 10px 24px;
border-color: transparent #5a8f00;
}
/* creates the smaller triangle */
.triangle-border.right:after {
top: 8px; /* value = (:before top) + (:before border-top) - (:after border-top) */
bottom: auto;
left: auto;
right: -21px; /* value = - border-left-width - border-right-width */
border-width: 9px 0 9px 21px;
border-color: transparent #fff;
}
#button-send + a > i.text-info {
/* stylelint-disable-next-line declaration-no-important */
color: black !important;
}
+50
View File
@@ -0,0 +1,50 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
$chattheme_cfg = new stdClass();
$chattheme_cfg->avatar = true;
$chattheme_cfg->align = true;
$chattheme_cfg->event_message = <<<TEMPLATE
<div class="chat-event">
<span class="time">___time___</span>
<a target='_blank' href="___senderprofile___">___sender___</a>
<span class="event">___event___</span>
</div>
TEMPLATE;
$chattheme_cfg->user_message_left = <<<TEMPLATE
<div class='chat-message ___mymessageclass___'>
<div class="left">
<span class="text triangle-border left">___message___</span>
<span class="picture">___avatar___</span>
</div>
<div class="chat-message-meta left">
<span class="time">___time___</span>
<span class="user">___sender___</span>
</div>
</div>
TEMPLATE;
$chattheme_cfg->user_message_right = <<<TEMPLATE
<div class='chat-message ___mymessageclass___'>
<div class="right">
<span class="text triangle-border right">___message___</span>
<span class="picture">___avatar___</span>
</div>
<div class="chat-message-meta right">
<span class="time">___time___</span>
<span class="user">___sender___</span>
</div>
</div>
TEMPLATE;
Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

+102
View File
@@ -0,0 +1,102 @@
.yui-skin-sam .yui-layout .yui-layout-hd {
border: 0;
}
.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd-nohd {
border: 0;
}
.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd {
border: 0;
}
.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-unit-right {
background: white;
}
.yui-skin-sam .yui-layout-unit-bottom {
background: #f2f2f2;
}
.yui-skin-sam .yui-layout-unit-right {
background: #eef2f8;
}
.yui-skin-sam .yui-layout-unit-center {
background: white;
}
.yui-skin-sam .yui-layout-unit-top {
background: #ffe39d;
}
.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd {
background: transparent;
}
#input-message {
background: #fff url(input.png) repeat-x scroll 0 0;
border: 1px solid #999;
}
.mdl-chat-entry .meta {
background: #82b5ee;
border-bottom: 1px solid white;
-moz-border-radius-topleft: 6px;
-moz-border-radius-topright: 6px;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
.mdl-chat-entry,
.mdl-chat-my-entry {
margin: 1em auto;
border: 1px solid #938f5a;
-moz-border-radius-bottomleft: 6px;
-moz-border-radius-bottomright: 6px;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
}
.mdl-chat-entry .chat-message .text {
color: white;
background: #82b5ee;
}
.chat-message {
padding: 3px;
border: 1px solid #ccc;
-moz-border-radius-bottomleft: 6px;
-moz-border-radius-bottomright: 6px;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
}
.mdl-chat-my-entry .chat-message .meta {
background: #fffeeb;
border-bottom: 1px solid white;
}
.mdl-chat-my-entry .chat-message .text {
background: #f1f3cb;
}
#chat-input-area,
#chat-input-area table.generaltable,
#chat-input-area table.generaltable td.cell {
background: #92b3e8;
border: 0;
margin: 0;
padding: 2px;
height: 100%;
}
#chat-userlist {
background: #e3e8f0;
height: 100%;
}
#button-send + a > i.text-info {
/* stylelint-disable-next-line declaration-no-important */
color: black !important;
}
@@ -0,0 +1,37 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
$chattheme_cfg = new stdClass();
$chattheme_cfg->avatar = false;
$chattheme_cfg->align = false;
$chattheme_cfg->event_message = <<<TEMPLATE
<div class="chat-event">
<span class="time">___time___</span>
<a target='_blank' href="___senderprofile___">___sender___</a>
<span class="event">___event___</span>
</div>
TEMPLATE;
$chattheme_cfg->user_message = <<<TEMPLATE
<div class='chat-message'>
<div class="chat-message-meta">
<span class="time">___time___</span>
<span class="user"><a href="___senderprofile___" target="_blank">___sender___</a></span>
</div>
<div class="text">
___message___
</div>
</div>
TEMPLATE;
Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

@@ -0,0 +1,37 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
$chattheme_cfg = new stdClass();
$chattheme_cfg->avatar = false;
$chattheme_cfg->align = false;
$chattheme_cfg->event_message = <<<TEMPLATE
<div class="chat-event course-theme">
<span class="time">___time___</span>
<a target='_blank' href="___senderprofile___">___sender___</a>
<span class="event">___event___</span>
</div>
TEMPLATE;
$chattheme_cfg->user_message = <<<TEMPLATE
<div class='chat-message course-theme'>
<div class="chat-message-meta">
<span class="time">___time___</span>
<span class="user"><a href="___senderprofile___" target="_blank">___sender___</a></span>
</div>
<div class="text">
___message___
</div>
</div>
TEMPLATE;
+213
View File
@@ -0,0 +1,213 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
require_once('../../../config.php');
require_once('../lib.php');
$id = required_param('id', PARAM_INT);
$groupid = optional_param('groupid', 0, PARAM_INT); // Only for teachers.
$message = optional_param('message', '', PARAM_CLEANHTML);
$refresh = optional_param('refresh', '', PARAM_RAW); // Force refresh.
$last = optional_param('last', 0, PARAM_INT); // Last time refresh or sending.
$newonly = optional_param('newonly', 0, PARAM_BOOL); // Show only new messages.
$url = new moodle_url('/mod/chat/gui_basic/index.php', array('id' => $id));
if ($groupid !== 0) {
$url->param('groupid', $groupid);
}
if ($message !== 0) {
$url->param('message', $message);
}
if ($refresh !== 0) {
$url->param('refresh', $refresh);
}
if ($last !== 0) {
$url->param('last', $last);
}
if ($newonly !== 0) {
$url->param('newonly', $newonly);
}
$PAGE->set_url($url);
if (!$chat = $DB->get_record('chat', array('id' => $id))) {
throw new \moodle_exception('invalidid', 'chat');
}
if (!$course = $DB->get_record('course', array('id' => $chat->course))) {
throw new \moodle_exception('invalidcourseid');
}
if (!$cm = get_coursemodule_from_instance('chat', $chat->id, $course->id)) {
throw new \moodle_exception('invalidcoursemodule');
}
$context = context_module::instance($cm->id);
require_login($course, false, $cm);
require_capability('mod/chat:chat', $context);
$PAGE->set_pagelayout('popup');
$PAGE->set_popup_notification_allowed(false);
// Check to see if groups are being used here.
if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used.
if ($groupid = groups_get_activity_group($cm)) {
if (!$group = groups_get_group($groupid)) {
throw new \moodle_exception('invalidgroupid');
}
$groupname = ': '.$group->name;
} else {
$groupname = ': '.get_string('allparticipants');
}
} else {
$groupid = 0;
$groupname = '';
}
$strchat = get_string('modulename', 'chat'); // Must be before current_language() in chat_login_user() to force course language!
$strchats = get_string('modulenameplural', 'chat');
$stridle = get_string('idle', 'chat');
if (!$chatsid = chat_login_user($chat->id, 'basic', $groupid, $course)) {
throw new \moodle_exception('cantlogin', 'chat');
}
if (!$chatusers = chat_get_users($chat->id, $groupid, $cm->groupingid)) {
throw new \moodle_exception('errornousers', 'chat');
}
$DB->set_field('chat_users', 'lastping', time(), array('sid' => $chatsid));
if (!isset($SESSION->chatprefs)) {
$SESSION->chatprefs = array();
}
if (!isset($SESSION->chatprefs[$chat->id])) {
$SESSION->chatprefs[$chat->id] = array();
$SESSION->chatprefs[$chat->id]['chatentered'] = time();
}
$chatentered = $SESSION->chatprefs[$chat->id]['chatentered'];
$refreshedmessage = '';
if (!empty($refresh) and data_submitted()) {
$refreshedmessage = $message;
chat_delete_old_users();
} else if (empty($refresh) and data_submitted() and confirm_sesskey()) {
if ($message != '') {
$chatuser = $DB->get_record('chat_users', array('sid' => $chatsid));
chat_send_chatmessage($chatuser, $message, 0, $cm);
$DB->set_field('chat_users', 'lastmessageping', time(), array('sid' => $chatsid));
}
chat_delete_old_users();
$url = new moodle_url('/mod/chat/gui_basic/index.php', array('id' => $id, 'newonly' => $newonly, 'last' => $last));
redirect($url);
}
$PAGE->set_title("$strchat: $course->shortname: ".format_string($chat->name, true)."$groupname");
echo $OUTPUT->header();
echo $OUTPUT->container_start(null, 'page-mod-chat-gui_basic');
echo $OUTPUT->heading(format_string($course->shortname), 1);
echo $OUTPUT->heading(format_string($chat->name), 2);
echo $OUTPUT->heading(get_string('participants'), 3);
echo $OUTPUT->box_start('generalbox', 'participants');
echo '<ul>';
foreach ($chatusers as $chu) {
echo '<li class="clearfix">';
echo $OUTPUT->user_picture($chu, array('size' => 24, 'courseid' => $course->id));
echo '<div class="userinfo">';
echo fullname($chu).' ';
if ($idle = time() - $chu->lastmessageping) {
echo '<span class="idle">'.$stridle.' '.format_time($idle).'</span>';
} else {
echo '<span class="idle" />';
}
echo '</div>';
echo '</li>';
}
echo '</ul>';
echo $OUTPUT->box_end();
echo '<div id="send">';
echo '<form id="editing" method="post" action="index.php">';
echo '<h2><label for="message">' . get_string('sendmessage', 'message');
echo $OUTPUT->help_icon('usingchat', 'chat');
echo '</label></h2>';
echo '<div class="mb-1">';
echo '<input type="text" id="message" class="form-control" name="message" value="'.s($refreshedmessage, true).'" size="60" />';
echo '</div><div class="mb-1">';
echo '<input type="hidden" name="id" value="'.$id.'" />';
echo '<input type="hidden" name="groupid" value="'.$groupid.'" />';
echo '<input type="hidden" name="last" value="'.time().'" />';
echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
echo '<input type="submit" class="btn btn-primary" value="'.get_string('submit').'" />&nbsp;';
echo '<input type="submit" class="btn btn-secondary" name="refresh" value="'.get_string('refresh').'" />';
echo '<input type="checkbox" class="mx-1" name="newonly" id="newonly" '.($newonly ? 'checked="checked" ' : '').'/>';
echo '<label for="newonly">'.get_string('newonlymsg', 'message').'</label>';
echo '</div>';
echo '</form>';
echo '</div>';
echo '<div id="messages">';
echo $OUTPUT->heading(get_string('messages', 'chat'), 3);
$allmessages = array();
$options = new stdClass();
$options->para = false;
$options->newlines = true;
$params = array('last' => $last, 'groupid' => $groupid, 'chatid' => $chat->id, 'chatentered' => $chatentered);
if ($newonly) {
$lastsql = "AND timestamp > :last";
} else {
$lastsql = "";
}
$groupselect = $groupid ? "AND (groupid=:groupid OR groupid=0)" : "";
$messages = $DB->get_records_select("chat_messages_current",
"chatid = :chatid AND timestamp > :chatentered $lastsql $groupselect", $params,
"timestamp DESC");
if ($messages) {
foreach ($messages as $message) {
$allmessages[] = chat_format_message($message, $course->id, $USER);
}
}
echo '<table class="generaltable"><tbody>';
echo '<tr>
<th scope="col" class="cell">' . get_string('fromsender') . '</th>
<th scope="col" class="cell">' . get_string('message', 'message') . '</th>
<th scope="col" class="cell">' . get_string('time') . '</th>
</tr>';
if (empty($allmessages)) {
echo get_string('nomessagesfound', 'message');
} else {
foreach ($allmessages as $message) {
echo $message->basic;
}
}
echo '</tbody></table>';
echo '</div>';
echo $OUTPUT->container_end();
echo $OUTPUT->footer();
+80
View File
@@ -0,0 +1,80 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
define('NO_MOODLE_COOKIES', true); // Session not used here.
require_once('../../../config.php');
require_once($CFG->dirroot.'/mod/chat/lib.php');
$chatsid = required_param('chat_sid', PARAM_ALPHANUM);
$chatid = required_param('chat_id', PARAM_INT);
if (!$chatuser = $DB->get_record('chat_users', array('sid' => $chatsid))) {
throw new \moodle_exception('notlogged', 'chat');
}
if (!$chat = $DB->get_record('chat', array('id' => $chatid))) {
throw new \moodle_exception('invalidid', 'chat');
}
if (!$course = $DB->get_record('course', array('id' => $chat->course))) {
throw new \moodle_exception('invalidcourseid');
}
if (!$cm = get_coursemodule_from_instance('chat', $chat->id, $course->id)) {
throw new \moodle_exception('invalidcoursemodule');
}
$PAGE->set_url('/mod/chat/gui_header_js/chatinput.php', array('chat_sid' => $chatsid, 'chat_id' => $chatid));
$PAGE->set_popup_notification_allowed(false);
// Get the user theme.
$USER = $DB->get_record('user', array('id' => $chatuser->userid));
$module = array(
'name' => 'mod_chat_header',
'fullpath' => '/mod/chat/gui_header_js/module.js',
'requires' => array('node')
);
$PAGE->requires->js_init_call('M.mod_chat_header.init_input', array(false), false, $module);
// Setup course, lang and theme.
$PAGE->set_course($course);
$PAGE->set_pagelayout('embedded');
$PAGE->set_focuscontrol('input_chat_message');
$PAGE->set_cacheable(false);
echo $OUTPUT->header();
echo html_writer::start_tag('form', array('action' => '../empty.php',
'method' => 'post',
'target' => 'empty',
'id' => 'inputForm',
'style' => 'margin:0'));
echo html_writer::label(get_string('entermessage', 'chat'), 'input_chat_message', false, array('class' => 'accesshide'));
echo html_writer::empty_tag('input', array('type' => 'text',
'id' => 'input_chat_message',
'name' => 'chat_message',
'size' => '50',
'value' => ''));
echo html_writer::empty_tag('input', array('type' => 'checkbox', 'id' => 'auto', 'checked' => 'checked', 'value' => ''));
echo html_writer::tag('label', get_string('autoscroll', 'chat'), array('for' => 'auto'));
echo html_writer::end_tag('form');
echo html_writer::start_tag('form', array('action' => 'insert.php', 'method' => 'post', 'target' => 'empty', 'id' => 'sendForm'));
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'chat_sid', 'value' => $chatsid));
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'chat_message', 'id' => 'insert_chat_message'));
echo html_writer::end_tag('form');
echo $OUTPUT->footer();
+8
View File
@@ -0,0 +1,8 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Dummy</title>
</head>
<body>
</body>
</html>
+100
View File
@@ -0,0 +1,100 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
require_once('../../../config.php');
require_once('../lib.php');
$id = required_param('id', PARAM_INT);
$groupid = optional_param('groupid', 0, PARAM_INT); // Only for teachers.
$url = new moodle_url('/mod/chat/gui_header_js/index.php', array('id' => $id));
if ($groupid !== 0) {
$url->param('groupid', $groupid);
}
$PAGE->set_url($url);
if (!$chat = $DB->get_record('chat', array('id' => $id))) {
throw new \moodle_exception('invalidid', 'chat');
}
if (!$course = $DB->get_record('course', array('id' => $chat->course))) {
throw new \moodle_exception('invalidcourseid');
}
if (!$cm = get_coursemodule_from_instance('chat', $chat->id, $course->id)) {
throw new \moodle_exception('invalidcoursemodule');
}
$context = context_module::instance($cm->id);
require_login($course, false, $cm);
require_capability('mod/chat:chat', $context);
// Check to see if groups are being used here.
if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used.
if ($groupid = groups_get_activity_group($cm)) {
if (!$group = groups_get_group($groupid)) {
throw new \moodle_exception('invalidgroupid');
}
$groupname = ': '.$group->name;
} else {
$groupname = ': '.get_string('allparticipants');
}
} else {
$groupid = 0;
$groupname = '';
}
$strchat = get_string('modulename', 'chat'); // Must be before current_language() in chat_login_user() to force course language!
if (!$chatsid = chat_login_user($chat->id, 'header_js', $groupid, $course)) {
throw new \moodle_exception('cantlogin', 'chat');
}
$params = "chat_id=$id&chat_sid={$chatsid}";
// Fallback to the old jsupdate, but allow other update modes.
$updatemode = 'jsupdate';
if (!empty($CFG->chat_normal_updatemode)) {
$updatemode = $CFG->chat_normal_updatemode;
}
$courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>
<?php echo "$strchat: " . $courseshortname . ": ".
format_string($chat->name, true, array('context' => $context)) . "$groupname" ?>
</title>
</head>
<frameset cols="*,200" border="5" framespacing="no" frameborder="yes" marginwidth="2" marginheight="1">
<frameset rows="0,0,*,50" border="0" framespacing="no" frameborder="no" marginwidth="2" marginheight="1">
<frame src="../empty.php" name="empty" scrolling="no" marginwidth="0" marginheight="0">
<frame src="<?php echo $updatemode ?>.php?<?php echo $params ?>" name="jsupdate" scrolling="no" marginwidth="0" marginheight="0">
<frame src="chatmsg.php?<?php echo $params ?>" name="msg" scrolling="auto" marginwidth="2" marginheight="1">
<frame src="chatinput.php?<?php echo $params ?>" name="input" scrolling="no" marginwidth="2" marginheight="1">
</frameset>
<frame src="users.php?<?php echo $params ?>" name="users" scrolling="auto" marginwidth="5" marginheight="5">
</frameset>
<noframes>
Sorry, this version of Moodle Chat needs a browser that handles frames.
</noframes>
</html>
+78
View File
@@ -0,0 +1,78 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
require_once('../../../config.php');
require_once('../lib.php');
$chatsid = required_param('chat_sid', PARAM_ALPHANUM);
$chatmessage = required_param('chat_message', PARAM_RAW);
$PAGE->set_url('/mod/chat/gui_header_js/insert.php', array('chat_sid' => $chatsid, 'chat_message' => $chatmessage));
if (!$chatuser = $DB->get_record('chat_users', array('sid' => $chatsid))) {
throw new \moodle_exception('notlogged', 'chat');
}
if (!$chat = $DB->get_record('chat', array('id' => $chatuser->chatid))) {
throw new \moodle_exception('nochat', 'chat');
}
if (!$course = $DB->get_record('course', array('id' => $chat->course))) {
throw new \moodle_exception('invalidcourseid');
}
if (!$cm = get_coursemodule_from_instance('chat', $chat->id, $course->id)) {
throw new \moodle_exception('invalidcoursemodule');
}
require_login($course, false, $cm);
if (isguestuser()) {
throw new \moodle_exception('noguests');
}
\core\session\manager::write_close();
// Delete old users now.
chat_delete_old_users();
// Clean up the message.
$chatmessage = clean_text($chatmessage, FORMAT_MOODLE); // Strip bad tags.
// Add the message to the database.
if (!empty($chatmessage)) {
chat_send_chatmessage($chatuser, $chatmessage, 0, $cm);
$chatuser->lastmessageping = time() - 2;
$DB->update_record('chat_users', $chatuser);
}
if ($chatuser->version == 'header_js') {
$forcerefreshasap = ($CFG->chat_normal_updatemode != 'jsupdated'); // See bug MDL-6791.
$module = array(
'name' => 'mod_chat_header',
'fullpath' => '/mod/chat/gui_header_js/module.js'
);
$PAGE->requires->js_init_call('M.mod_chat_header.init_insert_nojsupdated', array($forcerefreshasap), true, $module);
}
redirect('../empty.php');
+192
View File
@@ -0,0 +1,192 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
define('NO_MOODLE_COOKIES', true); // Session not used here.
require('../../../config.php');
require_once('../lib.php');
$chatsid = required_param('chat_sid', PARAM_ALPHANUM);
$chatlasttime = optional_param('chat_lasttime', 0, PARAM_INT);
$chatlastrow = optional_param('chat_lastrow', 1, PARAM_INT);
$url = new moodle_url('/mod/chat/gui_header_js/jsupdate.php', array('chat_sid' => $chatsid));
if ($chatlasttime !== 0) {
$url->param('chat_lasttime', $chatlasttime);
}
if ($chatlastrow !== 1) {
$url->param('chat_lastrow', $chatlastrow);
}
$PAGE->set_url($url);
if (!$chatuser = $DB->get_record('chat_users', array('sid' => $chatsid))) {
throw new \moodle_exception('notlogged', 'chat');
}
// Get the minimal course.
if (!$course = $DB->get_record('course', array('id' => $chatuser->course))) {
throw new \moodle_exception('invalidcourseid');
}
// Get the user theme and enough info to be used in chat_format_message() which passes it along to.
// No optimisation here, it would break again in future!
if (!$user = $DB->get_record('user', array('id' => $chatuser->userid, 'deleted' => 0, 'suspended' => 0))) {
throw new \moodle_exception('invaliduser');
}
\core\session\manager::set_user($user);
// Setup course, lang and theme.
$PAGE->set_course($course);
// Force deleting of timed out users if there is a silence in room or just entering.
if ((time() - $chatlasttime) > $CFG->chat_old_ping) {
// Must be done before chat_get_latest_message!
chat_delete_old_users();
}
if ($message = chat_get_latest_message($chatuser->chatid, $chatuser->groupid)) {
$chatnewlasttime = $message->timestamp;
} else {
$chatnewlasttime = 0;
}
if ($chatlasttime == 0) { // Display some previous messages.
$chatlasttime = time() - $CFG->chat_old_ping; // TO DO - any better value?
}
$timenow = time();
$params = array('groupid' => $chatuser->groupid, 'chatid' => $chatuser->chatid, 'lasttime' => $chatlasttime);
$groupselect = $chatuser->groupid ? " AND (groupid=:groupid OR groupid=0) " : "";
$messages = $DB->get_records_select("chat_messages_current",
"chatid = :chatid AND timestamp > :lasttime $groupselect", $params,
"timestamp ASC");
if ($messages) {
$num = count($messages);
} else {
$num = 0;
}
$chatnewrow = ($chatlastrow + $num) % 2;
// No &amp; in url, does not work in header!
$baseurl = "{$CFG->wwwroot}/mod/chat/gui_header_js/jsupdate.php?";
$refreshurl = $baseurl . "chat_sid=$chatsid&chat_lasttime=$chatnewlasttime&chat_lastrow=$chatnewrow";
$refreshurlamp = $baseurl . "chat_sid=$chatsid&amp;chat_lasttime=$chatnewlasttime&amp;chat_lastrow=$chatnewrow";
header('Expires: Sun, 28 Dec 1997 09:32:45 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
header('Content-Type: text/html; charset=utf-8');
header("Refresh: $CFG->chat_refresh_room; url=$refreshurl");
// Use ob to be able to send Content-Length headers.
// Needed for Keep-Alive to work.
ob_start();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script type="text/javascript">
//<![CDATA[
if (parent.msg && parent.msg.document.getElementById("msgStarted") == null) {
parent.msg.document.close();
parent.msg.document.open("text/html","replace");
parent.msg.document.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
parent.msg.document.write("<html><head>");
parent.msg.document.write("<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />");
parent.msg.document.write("<base target=\"_blank\" />");
parent.msg.document.write("<\/head><body class=\"mod-chat-gui_header_js course-<?php echo $chatuser->course ?>\" id=\"mod-chat-gui_header_js-jsupdate\"><div style=\"display: none\" id=\"msgStarted\">&nbsp;<\/div>");
}
<?php
$beep = false;
$refreshusers = false;
$us = array ();
if (($chatlasttime != $chatnewlasttime) and $messages) {
foreach ($messages as $message) {
$chatlastrow = ($chatlastrow + 1) % 2;
$formatmessage = chat_format_message($message, $chatuser->course, $USER, $chatlastrow);
if ($formatmessage->beep) {
$beep = true;
}
if ($formatmessage->refreshusers) {
$refreshusers = true;
}
$us[$message->userid] = $timenow - $message->timestamp;
echo "if(parent.msg)";
echo "parent.msg.document.write('".addslashes_js($formatmessage->html)."\\n');\n";
}
}
$chatuser->lastping = time();
$DB->set_field('chat_users', 'lastping', $chatuser->lastping, array('id' => $chatuser->id));
if ($refreshusers) {
?>
var link = parent.users.document.getElementById('refreshLink');
if (link != null) {
parent.users.location.href = link.href;
}
<?php
} else {
foreach ($us as $uid => $lastping) {
$min = (int) ($lastping / 60);
$sec = $lastping - ($min * 60);
$min = $min < 10 ? '0'.$min : $min;
$sec = $sec < 10 ? '0'.$sec : $sec;
$idle = $min.':'.$sec;
echo "if (parent.users && parent.users.document.getElementById('uidle{$uid}') != null) {".
"parent.users.document.getElementById('uidle{$uid}').innerHTML = '$idle';}\n";
}
}
?>
if (parent.input) {
var autoscroll = parent.input.document.getElementById('auto');
if (parent.msg && autoscroll && autoscroll.checked) {
parent.msg.scroll(1,5000000);
}
}
//]]>
</script>
</head>
<body>
<?php
if ($beep) {
echo '<script> (function() {';
echo 'var audioElement = document.createElement("audio");';
echo 'audioElement.setAttribute("src", "../beep.mp3");';
echo 'audioElement.play(); })();';
echo '</script>';
}
?>
<a href="<?php echo $refreshurlamp ?>" name="refreshLink">Refresh link</a>
</body>
</html>
<?php
// Support HTTP Keep-Alive.
header("Content-Length: " . ob_get_length() );
ob_end_flush();
exit;
+248
View File
@@ -0,0 +1,248 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/** jsupdated.php - notes by Martin Langhoff <martin@catalyst.net.nz>
**
** This is an alternative version of jsupdate.php that acts
** as a long-running daemon. It will feed/stall/feed JS updates
** to the client. From the module configuration select "Stream"
** updates.
**
** The client connection is not forever though. Once we reach
** CHAT_MAX_CLIENT_UPDATES, it will force the client to re-fetch it.
**
** This buys us all the benefits that chatd has, minus the setup,
** as we are using apache to do the daemon handling.
**
**/
define('CHAT_MAX_CLIENT_UPDATES', 1000);
define('NO_MOODLE_COOKIES', true); // Session not used here.
define('NO_OUTPUT_BUFFERING', true);
require('../../../config.php');
require_once('../lib.php');
// We are going to run for a long time.
// Avoid being terminated by php.
core_php_time_limit::raise();
$chatsid = required_param('chat_sid', PARAM_ALPHANUM);
$chatlasttime = optional_param('chat_lasttime', 0, PARAM_INT);
$chatlastrow = optional_param('chat_lastrow', 1, PARAM_INT);
$chatlastid = optional_param('chat_lastid', 0, PARAM_INT);
$url = new moodle_url('/mod/chat/gui_header_js/jsupdated.php', array('chat_sid' => $chatsid));
if ($chatlasttime !== 0) {
$url->param('chat_lasttime', $chatlasttime);
}
if ($chatlastrow !== 1) {
$url->param('chat_lastrow', $chatlastrow);
}
if ($chatlastid !== 1) {
$url->param('chat_lastid', $chatlastid);
}
$PAGE->set_url($url);
if (!$chatuser = $DB->get_record('chat_users', array('sid' => $chatsid))) {
throw new \moodle_exception('notlogged', 'chat');
}
// Get the minimal course.
if (!$course = $DB->get_record('course', array('id' => $chatuser->course))) {
throw new \moodle_exception('invalidcourseid');
}
// Get the user theme and enough info to be used in chat_format_message() which passes it along to
// chat_format_message_manually() -- and only id and timezone are used.
// No optimisation here, it would break again in future!
if (!$user = $DB->get_record('user', array('id' => $chatuser->userid, 'deleted' => 0, 'suspended' => 0))) {
throw new \moodle_exception('invaliduser');
}
\core\session\manager::set_user($user);
// Setup course, lang and theme.
$PAGE->set_course($course);
// Force deleting of timed out users if there is a silence in room or just entering.
if ((time() - $chatlasttime) > $CFG->chat_old_ping) {
// Must be done before chat_get_latest_message!
chat_delete_old_users();
}
// Time to send headers, and lay out the basic JS updater page.
header('Expires: Sun, 28 Dec 1997 09:32:45 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
header('Content-Type: text/html; charset=utf-8');
$refreshurl = "{$CFG->wwwroot}/mod/chat/gui_header_js/jsupdated.php?".
"chat_sid=$chatsid&chat_lasttime=$chatlasttime&chat_lastrow=$chatnewrow&chat_lastid=$chatlastid";
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script type="text/javascript">
//<![CDATA[
if (parent.msg.document.getElementById("msgStarted") == null) {
parent.msg.document.close();
parent.msg.document.open("text/html","replace");
parent.msg.document.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
parent.msg.document.write("<html><head>");
parent.msg.document.write("<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />");
parent.msg.document.write("<base target=\"_blank\" />");
parent.msg.document.write("</head><body class=\"mod-chat-gui_header_js course-<?php echo $chatuser->course ?>\" id=\"mod-chat-gui_header_js-jsupdate\"><div style=\"display: none\" id=\"msgStarted\">&nbsp;</div>");
}
//]]>
</script>
</head>
<body>
<?php
// Ensure the HTML head makes it out there.
echo $CHAT_DUMMY_DATA;
for ($n = 0; $n <= CHAT_MAX_CLIENT_UPDATES; $n++) {
// Ping first so we can later shortcut as needed.
$chatuser->lastping = time();
$DB->set_field('chat_users', 'lastping', $chatuser->lastping, array('id' => $chatuser->id));
if ($message = chat_get_latest_message($chatuser->chatid, $chatuser->groupid)) {
$chatnewlasttime = $message->timestamp;
$chatnewlastid = $message->id;
} else {
$chatnewlasttime = 0;
$chatnewlastid = 0;
print " \n";
print $CHAT_DUMMY_DATA;
sleep($CFG->chat_refresh_room);
continue;
}
$timenow = time();
$params = array('groupid' => $chatuser->groupid,
'lastid' => $chatlastid,
'lasttime' => $chatlasttime,
'chatid' => $chatuser->chatid);
$groupselect = $chatuser->groupid ? " AND (groupid=:groupid OR groupid=0) " : "";
$newcriteria = '';
if ($chatlastid > 0) {
$newcriteria = "id > :lastid";
} else {
if ($chatlasttime == 0) { // Display some previous messages.
$chatlasttime = $timenow - $CFG->chat_old_ping; // TO DO - any better value?
}
$newcriteria = "timestamp > :lasttime";
}
$messages = $DB->get_records_select("chat_messages_current",
"chatid = :chatid AND $newcriteria $groupselect", $params,
"timestamp ASC");
if ($messages) {
$num = count($messages);
} else {
print " \n";
print $CHAT_DUMMY_DATA;
sleep($CFG->chat_refresh_room);
continue;
}
print '<script type="text/javascript">' . "\n";
print "//<![CDATA[\n\n";
$chatnewrow = ($chatlastrow + $num) % 2;
$refreshusers = false;
$us = array ();
if (($chatlasttime != $chatnewlasttime) and $messages) {
$beep = false;
$refreshusers = false;
foreach ($messages as $message) {
$chatlastrow = ($chatlastrow + 1) % 2;
$formatmessage = chat_format_message($message, $chatuser->course, $USER, $chatlastrow);
if ($formatmessage->beep) {
$beep = true;
}
if ($formatmessage->refreshusers) {
$refreshusers = true;
}
$us[$message->userid] = $timenow - $message->timestamp;
echo "parent.msg.document.write('".addslashes_js($formatmessage->html )."\\n');\n";
}
// From the last message printed.
// A strange case where lack of closures is useful!
$chatlasttime = $message->timestamp;
$chatlastid = $message->id;
}
if ($refreshusers) {
echo "if (parent.users.document.anchors[0] != null) {" .
"parent.users.location.href = parent.users.document.anchors[0].href;}\n";
} else {
foreach ($us as $uid => $lastping) {
$min = (int) ($lastping / 60);
$sec = $lastping - ($min * 60);
$min = $min < 10 ? '0'.$min : $min;
$sec = $sec < 10 ? '0'.$sec : $sec;
$idle = $min.':'.$sec;
echo "if (parent.users.document.getElementById('uidle{$uid}') != null) {".
"parent.users.document.getElementById('uidle{$uid}').innerHTML = '$idle';}\n";
}
}
print <<<EOD
if(parent.input){
var autoscroll = parent.input.document.getElementById('auto');
if(parent.msg && autoscroll && autoscroll.checked){
parent.msg.scroll(1,5000000);
}
}
EOD;
print "//]]>\n";
print '</script>' . "\n\n";
if ($beep) {
print '<script> (function() {';
print 'var audioElement = document.createElement("audio");';
print 'audioElement.setAttribute("src", "../beep.mp3");';
print 'audioElement.play(); })();';
print '</script>';
}
print $CHAT_DUMMY_DATA;
sleep($CFG->chat_refresh_room);
} // Here ends the for() loop.
// Here & should be written & :-D.
$refreshurl = "{$CFG->wwwroot}/mod/chat/gui_header_js/jsupdated.php?";
$refreshurl .= "chat_sid=$chatsid&chat_lasttime=$chatlasttime&chat_lastrow=$chatnewrow&chat_lastid=$chatlastid";
print '<script type="text/javascript">' . "\n";
print "//<![CDATA[ \n\n";
print "location.href = '$refreshurl';\n";
print "//]]>\n";
print '</script>' . "\n\n";
?>
</body>
</html>
+150
View File
@@ -0,0 +1,150 @@
/*
* NOTE: the /mod/chat/gui_header_js/ is not a real plugin,
* ideally this code should be in /mod/chat/module.js
*/
/**
* @namespace M.mod_chat_header
*/
M.mod_chat_header = M.mod_chat_ajax || {};
/**
* Init header based Chat UI - frame input
*
* @namespace M.mod_chat_header
* @function
* @param {YUI} Y
* @param {Boolean} forcerefreshasap refresh users frame asap
*/
M.mod_chat_header.init_insert = function(Y, forcerefreshasap) {
if (forcerefreshasap) {
parent.jsupdate.location.href = parent.jsupdate.document.anchors[0].href;
}
parent.input.enableForm();
};
/**
* Init header based Chat UI - frame input
*
* @namespace M.mod_chat_header
* @function
* @param {YUI} Y
*/
M.mod_chat_header.init_input = function(Y) {
var inputframe = {
waitflag : false, // True when a submission is in progress
/**
* Initialises the input frame
*
* @function
*/
init : function() {
Y.one('#inputForm').on('submit', this.submit, this);
},
/**
* Enables the input form
* @this {M.mod_chat.js}
*/
enable_form : function() {
var el = Y.one('#input_chat_message');
this.waitflag = false;
el.set('className', '');
el.focus();
},
/**
* Submits the entered message
* @param {Event} e
*/
submit : function(e) {
e.halt();
if (this.waitflag) {
return false;
}
this.waitflag = true;
var inputchatmessage = Y.one('#input_chat_message');
Y.one('#insert_chat_message').set('value', inputchatmessage.get('value'));
inputchatmessage.set('value', '');
inputchatmessage.addClass('wait');
Y.one('#sendForm').submit();
this.enable_form();
return false;
}
};
inputframe.init();
};
/**
* Init header based Chat UI - frame users
*
* @namespace M.mod_chat_header
* @function
* @param {YUI} Y
* @param {Array} users
*/
M.mod_chat_header.init_users = function(Y, users) {
var usersframe = {
timer : null, // Stores the timer object
timeout : 1, // The seconds between updates
users : [], // An array of users
/**
* Initialises the frame with list of users
*
* @function
* @this
* @param {Array|null} users
*/
init : function(users) {
this.users = users;
this.start();
Y.one(document.body).on('unload', this.stop, this);
},
/**
* Starts the update timeout
*
* @function
* @this
*/
start : function() {
this.timer = setTimeout(function(self) {
self.update();
}, this.timeout * 1000, this);
},
/**
* Stops the update timeout
* @function
* @this
*/
stop : function() {
clearTimeout(this.timer);
},
/**
* Updates the user information
*
* @function
* @this
*/
update : function() {
for (var i in this.users) {
var el = Y.one('#uidle' + this.users[i]);
if (el) {
var parts = el.get('innerHTML').split(':');
var time = this.timeout + (parseInt(parts[0], 10) * 60) + parseInt(parts[1], 10);
var min = Math.floor(time / 60);
var sec = time % 60;
el.set('innerHTML', ((min < 10) ? "0" : "") + min + ":" + ((sec < 10) ? "0" : "") + sec);
}
}
this.start();
}
};
usersframe.init(users);
};
+141
View File
@@ -0,0 +1,141 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
define('NO_MOODLE_COOKIES', true); // Session not used here.
require_once('../../../config.php');
require_once($CFG->dirroot.'/mod/chat/lib.php');
$chatsid = required_param('chat_sid', PARAM_ALPHANUM);
$beep = optional_param('beep', 0, PARAM_INT); // Beep target.
$PAGE->set_url('/mod/chat/gui_header_js/users.php', array('chat_sid' => $chatsid));
$PAGE->set_popup_notification_allowed(false);
if (!$chatuser = $DB->get_record('chat_users', array('sid' => $chatsid))) {
throw new \moodle_exception('notlogged', 'chat');
}
// Get the minimal course.
if (!$course = $DB->get_record('course', array('id' => $chatuser->course))) {
throw new \moodle_exception('invalidcourseid');
}
// Get the user theme and enough info to be used in chat_format_message() which passes it along to.
// No optimisation here, it would break again in future!
if (!$user = $DB->get_record('user', array('id' => $chatuser->userid, 'deleted' => 0, 'suspended' => 0))) {
throw new \moodle_exception('invaliduser');
}
\core\session\manager::set_user($user);
$PAGE->set_pagelayout('embedded');
// Setup course, lang and theme.
$PAGE->set_course($course);
$courseid = $chatuser->course;
if (!$cm = get_coursemodule_from_instance('chat', $chatuser->chatid, $courseid)) {
throw new \moodle_exception('invalidcoursemodule');
}
if ($beep) {
chat_send_chatmessage($chatuser, "beep $beep", 0, $cm);
$chatuser->lastmessageping = time(); // A beep is a ping.
}
$chatuser->lastping = time();
$DB->set_field('chat_users', 'lastping', $chatuser->lastping, array('id' => $chatuser->id));
$refreshurl = "users.php?chat_sid=$chatsid";
// Get list of users.
if (!$chatusers = chat_get_users($chatuser->chatid, $chatuser->groupid, $cm->groupingid)) {
throw new \moodle_exception('errornousers', 'chat');
}
$uidles = Array();
foreach ($chatusers as $chatuser) {
$uidles[] = $chatuser->id;
}
$module = array(
'name' => 'mod_chat_header',
'fullpath' => '/mod/chat/gui_header_js/module.js',
'requires' => array('node')
);
$PAGE->requires->js_init_call('M.mod_chat_header.init_users', array($uidles), false, $module);
// Print user panel body.
$timenow = time();
$stridle = get_string('idle', 'chat');
$strbeep = get_string('beep', 'chat');
$table = new html_table();
$table->width = '100%';
$table->data = array();
foreach ($chatusers as $chatuser) {
$lastping = $timenow - $chatuser->lastmessageping;
$min = (int) ($lastping / 60);
$sec = $lastping - ($min * 60);
$min = $min < 10 ? '0'.$min : $min;
$sec = $sec < 10 ? '0'.$sec : $sec;
$idle = $min.':'.$sec;
$row = array();
$row[0] = $OUTPUT->user_picture($chatuser, array('courseid' => $courseid, 'popup' => true));
$row[1] = html_writer::start_tag('p');
$row[1] .= html_writer::start_tag('font', array('size' => '1'));
$row[1] .= fullname($chatuser).'<br />';
$row[1] .= html_writer::tag('span', $stridle . html_writer::tag('span',
$idle,
array('name' => 'uidles', 'id' => 'uidle'.$chatuser->id)),
array('class' => 'dimmed_text')) . ' ';
$row[1] .= html_writer::tag('a', $strbeep, array('href' => new moodle_url('/mod/chat/gui_header_js/users.php',
array('chat_sid' => $chatsid,
'beep' => $chatuser->id))));
$row[1] .= html_writer::end_tag('font');
$row[1] .= html_writer::end_tag('p');
$table->data[] = $row;
}
ob_start();
echo $OUTPUT->header();
echo html_writer::tag('div', html_writer::tag('a', get_string('refresh'),
array('href' => $refreshurl, 'id' => 'refreshLink')), array('style' => 'display:none'));
echo html_writer::table($table);
echo $OUTPUT->footer();
// Support HTTP Keep-Alive by printing Content-Length
//
// If the user pane is refreshing often, using keepalives
// is lighter on the server and faster for most clients.
//
// Apache is normally configured to have a 15s timeout on
// keepalives, so let's observe that. Unfortunately, we cannot
// autodetect the keepalive timeout.
//
// Using keepalives when the refresh is longer than the timeout
// wastes server resources keeping an apache child around on a
// connection that will timeout. So we don't.
if ($CFG->chat_refresh_userlist < 15) {
header("Content-Length: " . ob_get_length() );
ob_end_flush();
}
exit; // No further output.
+14
View File
@@ -0,0 +1,14 @@
scroll_active = true;
function empty_field_and_submit() {
var cf = document.getElementById('sendform');
var inpf = document.getElementById('inputform');
cf.chat_msgidnr.value = parseInt(cf.chat_msgidnr.value) + 1;
cf.chat_message.value = inpf.chat_message.value;
inpf.chat_message.value = '';
cf.submit();
inpf.chat_message.focus();
return false;
}
function setfocus() {
document.getElementsByName("chat_message")[0].focus();
}
+59
View File
@@ -0,0 +1,59 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
define('NO_MOODLE_COOKIES', true); // Session not used here.
require('../../../config.php');
require_once('../lib.php');
$chatsid = required_param('chat_sid', PARAM_ALPHANUM);
$PAGE->set_url('/mod/chat/gui_sockets/chatinput.php', array('chat_sid' => $chatsid));
$PAGE->set_popup_notification_allowed(false);
if (!$chatuser = $DB->get_record('chat_users', array('sid' => $chatsid))) {
throw new \moodle_exception('notlogged', 'chat');
}
// Get the user theme.
$USER = $DB->get_record('user', array('id' => $chatuser->userid));
// Setup course, lang and theme.
$PAGE->set_pagelayout('embedded');
$PAGE->set_course($DB->get_record('course', array('id' => $chatuser->course)));
$PAGE->requires->js('/mod/chat/gui_sockets/chat_gui_sockets.js', true);
$PAGE->requires->js_function_call('setfocus');
$PAGE->set_focuscontrol('chat_message');
$PAGE->set_cacheable(false);
echo $OUTPUT->header();
?>
<form action="../empty.php" method="get" target="empty" id="inputform"
onsubmit="return empty_field_and_submit();">
<label class="accesshide" for="chat_message"><?php print_string('entermessage', 'chat'); ?></label>
<input type="text" name="chat_message" id="chat_message" size="60" value="" />
</form>
<form action="<?php echo "http://$CFG->chat_serverhost:$CFG->chat_serverport/"; ?>" method="get" target="empty" id="sendform">
<input type="hidden" name="win" value="message" />
<input type="hidden" name="chat_message" value="" />
<input type="hidden" name="chat_msgidnr" value="0" />
<input type="hidden" name="chat_sid" value="<?php echo $chatsid ?>" />
</form>
<?php
echo $OUTPUT->footer();
+92
View File
@@ -0,0 +1,92 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
require_once('../../../config.php');
require_once('../lib.php');
$id = required_param('id', PARAM_INT);
$groupid = optional_param('groupid', 0, PARAM_INT); // Only for teachers.
$url = new moodle_url('/mod/chat/gui_sockets/index.php', array('id' => $id));
if ($groupid !== 0) {
$url->param('groupid', $groupid);
}
$PAGE->set_url($url);
if (!$chat = $DB->get_record('chat', array('id' => $id))) {
throw new \moodle_exception('invalidid', 'chat');
}
if (!$course = $DB->get_record('course', array('id' => $chat->course))) {
throw new \moodle_exception('invalidcourseid');
}
if (!$cm = get_coursemodule_from_instance('chat', $chat->id, $course->id)) {
throw new \moodle_exception('invalidcoursemodule');
}
require_login($course, false, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/chat:chat', $context);
// Check to see if groups are being used here
if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used.
if ($groupid = groups_get_activity_group($cm)) {
if (!$group = groups_get_group($groupid)) {
throw new \moodle_exception('invalidgroupid');
}
$groupname = ': '.$group->name;
} else {
$groupname = ': '.get_string('allparticipants');
}
} else {
$groupid = 0;
$groupname = '';
}
$strchat = get_string('modulename', 'chat'); // Must be before current_language() in chat_login_user() to force course language!
if (!$chatsid = chat_login_user($chat->id, 'sockets', $groupid, $course)) {
throw new \moodle_exception('cantlogin');
}
$params = "chat_sid=$chatsid";
$courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
$chatname = format_string($chat->name, true, array('context' => $context));
$winchaturl = "http://$CFG->chat_serverhost:$CFG->chat_serverport?win=chat&amp;$params";
$winusersurl = "http://$CFG->chat_serverhost:$CFG->chat_serverport?win=users&amp;$params"
?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>
<?php echo "$strchat: " . $courseshortname . ": " . $chatname . "$groupname" ?>
</title>
</head>
<frameset cols="*,200" border="5" framespacing="no" frameborder="yes" marginwidth="2" marginheight="1">
<frameset rows="0,*,70" border="0" framespacing="no" frameborder="no" marginwidth="2" marginheight="1">
<frame src="../empty.php" name="empty" scrolling="auto" noresize marginwidth="2" marginheight="0">
<frame src="<?php echo $winchaturl; ?>" scrolling="auto" name="msg" noresize marginwidth="2" marginheight="0">
<frame src="chatinput.php?<?php echo $params ?>" name="input" scrolling="no" marginwidth="2" marginheight="1">
</frameset>
<frame src="<?php echo $winusersurl; ?>" name="users" scrolling="auto" marginwidth="5" marginheight="5">
</frameset>
<noframes>
Sorry, this version of Moodle Chat needs a browser that handles frames.
</noframes>
</html>
+106
View File
@@ -0,0 +1,106 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
require_once('../../config.php');
require_once('lib.php');
$id = required_param('id', PARAM_INT); // Course.
$PAGE->set_url('/mod/chat/index.php', array('id' => $id));
if (! $course = $DB->get_record('course', array('id' => $id))) {
throw new \moodle_exception('invalidcourseid');
}
require_course_login($course);
$PAGE->set_pagelayout('incourse');
$params = array(
'context' => context_course::instance($id)
);
$event = \mod_chat\event\course_module_instance_list_viewed::create($params);
$event->add_record_snapshot('course', $course);
$event->trigger();
// Get all required strings.
$strchats = get_string('modulenameplural', 'chat');
$strchat = get_string('modulename', 'chat');
// Print the header.
$PAGE->navbar->add($strchats);
$PAGE->set_title($strchats);
$PAGE->set_heading($course->fullname);
echo $OUTPUT->header();
echo $OUTPUT->heading($strchats, 2);
// Get all the appropriate data.
if (! $chats = get_all_instances_in_course('chat', $course)) {
notice(get_string('thereareno', 'moodle', $strchats), "../../course/view.php?id=$course->id");
die();
}
$usesections = course_format_uses_sections($course->format);
// Print the list of instances (your module will probably extend this).
$timenow = time();
$strname = get_string('name');
$table = new html_table();
if ($usesections) {
$strsectionname = get_string('sectionname', 'format_'.$course->format);
$table->head = array ($strsectionname, $strname);
$table->align = array ('center', 'left');
} else {
$table->head = array ($strname);
$table->align = array ('left');
}
$currentsection = '';
foreach ($chats as $chat) {
if (!$chat->visible) {
// Show dimmed if the mod is hidden.
$link = "<a class=\"dimmed\" href=\"view.php?id=$chat->coursemodule\">".format_string($chat->name, true)."</a>";
} else {
// Show normal if the mod is visible.
$link = "<a href=\"view.php?id=$chat->coursemodule\">".format_string($chat->name, true)."</a>";
}
$printsection = '';
if ($chat->section !== $currentsection) {
if ($chat->section) {
$printsection = get_section_name($course, $chat->section);
}
if ($currentsection !== '') {
$table->data[] = 'hr';
}
$currentsection = $chat->section;
}
if ($usesections) {
$table->data[] = array ($printsection, $link);
} else {
$table->data[] = array ($link);
}
}
echo '<br />';
echo html_writer::table($table);
// Finish the page.
echo $OUTPUT->footer();
+177
View File
@@ -0,0 +1,177 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Strings for component 'chat', language 'en', branch 'MOODLE_20_STABLE'
*
* @package mod_chat
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['activityoverview'] = 'You have upcoming chat sessions';
$string['ajax'] = 'Version using AJAX';
$string['autoscroll'] = 'Auto scroll';
$string['beep'] = 'Beep';
$string['bubble'] = 'Bubble';
$string['cantlogin'] = 'Could not log in to chat room!!';
$string['composemessage'] = 'Compose a message';
$string['configmethod'] = 'The AJAX chat method provide an AJAX-based chat interface which contacts the server regularly for updates. The normal chat method involves clients regularly contacting the server for updates. It requires no configuration and works everywhere, but can create a large load on the server if many users are chatting. Using a server daemon requires shell access to Unix, but it results in a fast scalable chat environment.';
$string['confignormalupdatemode'] = 'Chatroom updates are normally served efficiently using the <em>Keep-Alive</em> feature of HTTP 1.1, but this is still quite heavy on the server. A more advanced method is to use the <em>Stream</em> strategy to feed updates to the users. Using <em>Stream</em> scales much better (similar to the chatd method) but may not be supported by your server.';
$string['configoldping'] = 'What is the maximum time that may pass before we detect that a user has disconnected (in seconds)? This is just an upper limit, as usually disconnects are detected very quickly. Lower values will be more demanding on your server. If you are using the normal method, <strong>never</strong> set this lower than 2 * chat_refresh_room.';
$string['configrefreshroom'] = 'How often should the chat room itself be refreshed? (in seconds). Setting this low will make the chat room seem quicker, but it may place a higher load on your web server when many people are chatting. If you are using <em>Stream</em> updates, you can select higher refresh frequencies -- try with 2.';
$string['configrefreshuserlist'] = 'How often should the list of users be refreshed? (in seconds)';
$string['configserverhost'] = 'The hostname of the computer where the server daemon is';
$string['configserverip'] = 'The numerical IP address that matches the above hostname';
$string['configservermax'] = 'Max number of clients allowed';
$string['configserverport'] = 'Port to use on the server for the daemon';
$string['compact'] = 'Compact';
$string['coursetheme'] = 'Course theme';
$string['crontask'] = 'Background processing for chat module';
$string['currentchats'] = 'Active chat sessions';
$string['currentusers'] = 'Current users';
$string['deletesession'] = 'Delete this session';
$string['deletesessionsure'] = 'Are you sure you want to delete this session?';
$string['donotusechattime'] = 'Don\'t publish any chat times';
$string['enterchat'] = 'Enter the chat';
$string['errornousers'] = 'Could not find any users!';
$string['explaingeneralconfig'] = 'These settings are <strong>always</strong> used';
$string['explainmethoddaemon'] = 'These settings only have an effect if \'Chat server daemon\' is selected as chat method.';
$string['explainmethodnormal'] = 'These settings only have an effect if Normal is selected as chat method.';
$string['generalconfig'] = 'General configuration';
$string['chat:addinstance'] = 'Add a new chat';
$string['chat:deletelog'] = 'Delete chat logs';
$string['chat:exportparticipatedsession'] = 'Export chat session which you took part in';
$string['chat:exportsession'] = 'Export any chat session';
$string['chat:chat'] = 'Access a chat room';
$string['chatintro'] = 'Description';
$string['chatname'] = 'Name of this chat room';
$string['chat:readlog'] = 'View chat logs';
$string['chatreport'] = 'Chat sessions';
$string['chat:talk'] = 'Talk in a chat';
$string['chattime'] = 'Next chat time';
$string['nextchattime'] = 'Next chat time:';
$string['chat:view'] = 'View chat activity';
$string['entermessage'] = "Enter your message";
$string['eventmessagesent'] = 'Message sent';
$string['eventsessionsviewed'] = 'Sessions viewed';
$string['idle'] = 'Idle';
$string['indicator:cognitivedepth'] = 'Chat cognitive';
$string['indicator:cognitivedepth_help'] = 'This indicator is based on the cognitive depth reached by the student in a Chat activity.';
$string['indicator:cognitivedepthdef'] = 'Chat cognitive';
$string['indicator:cognitivedepthdef_help'] = 'The participant has reached this percentage of the cognitive engagement offered by the Chat activities during this analysis interval (Levels = No view, View, Submit, View feedback, Comment on feedback)';
$string['indicator:cognitivedepthdef_link'] = 'Learning_analytics_indicators#Cognitive_depth';
$string['indicator:socialbreadth'] = 'Chat social';
$string['indicator:socialbreadth_help'] = 'This indicator is based on the social breadth reached by the student in a Chat activity.';
$string['indicator:socialbreadthdef'] = 'Chat social';
$string['indicator:socialbreadthdef_help'] = 'The participant has reached this percentage of the social engagement offered by the Chat activities during this analysis interval (Levels = No participation, Participant alone, Participant with others)';
$string['indicator:socialbreadthdef_link'] = 'Learning_analytics_indicators#Social_breadth';
$string['inputarea'] = 'Input area';
$string['invalidid'] = 'Could not find that chat room!';
$string['list_all_sessions'] = 'List all sessions.';
$string['list_complete_sessions'] = 'List just complete sessions.';
$string['listing_all_sessions'] = 'Listing all sessions.';
$string['messagebeepseveryone'] = '{$a} beeps everyone!';
$string['messagebeepsyou'] = '{$a} has just beeped you!';
$string['messageenter'] = '{$a} has just entered this chat';
$string['messageexit'] = '{$a} has left this chat';
$string['messages'] = 'Messages';
$string['messageyoubeep'] = 'You beeped {$a}';
$string['method'] = 'Chat method';
$string['methoddaemon'] = 'Chat server daemon';
$string['methodnormal'] = 'Normal';
$string['methodajax'] = 'AJAX';
$string['modulename'] = 'Chat';
$string['modulename_help'] = 'The chat activity module enables participants to have text-based, real-time synchronous discussions.
The chat may be a one-time activity or it may be repeated at the same time each day or each week. Chat sessions are saved and can be made available for everyone to view or restricted to users with the capability to view chat session logs.
Chats are especially useful when the group chatting is not able to meet face-to-face, such as
* Regular meetings of students participating in online courses to enable them to share experiences with others in the same course but in a different location
* A student temporarily unable to attend in person chatting with their teacher to catch up with work
* Students out on work experience getting together to discuss their experiences with each other and their teacher
* Younger children using chat at home in the evenings as a controlled (monitored) introduction to the world of social networking
* A question and answer session with an invited speaker in a different location
* Sessions to help students prepare for tests where the teacher, or other students, would pose sample questions';
$string['modulename_link'] = 'mod/chat/view';
$string['modulenameplural'] = 'Chats';
$string['neverdeletemessages'] = 'Never delete messages';
$string['no_complete_sessions_found'] = 'No complete sessions found.';
$string['noguests'] = 'The chat is not open to guests';
$string['nochat'] = 'No chat found';
$string['nomessages'] = 'No messages yet';
$string['normalkeepalive'] = 'KeepAlive';
$string['normalstream'] = 'Stream';
$string['noscheduledsession'] = 'No scheduled session';
$string['notallowenter'] = 'You are not allowed to enter the chat room.';
$string['notlogged'] = 'You are not logged in!';
$string['nopermissiontoseethechatlog'] = 'You don\'t have permission to see the chat logs.';
$string['oldping'] = 'Disconnect timeout';
$string['page-mod-chat-x'] = 'Any chat module page';
$string['pastchats'] = 'Past chat sessions';
$string['pastsessions'] = 'Past sessions';
$string['pluginadministration'] = 'Chat administration';
$string['pluginname'] = 'Chat';
$string['privacy:metadata:chat_messages_current'] = 'Current chat session. This data is temporary and is deleted after the chat session is deleted';
$string['privacy:metadata:chat_users'] = 'Keeps track of which users are in which chat rooms';
$string['privacy:metadata:chat_users:firstping'] = 'Time of the first access to chat room';
$string['privacy:metadata:chat_users:ip'] = 'User IP';
$string['privacy:metadata:chat_users:lang'] = 'User language';
$string['privacy:metadata:chat_users:lastmessageping'] = 'Time of the last message in this chat room';
$string['privacy:metadata:chat_users:lastping'] = 'Time of the last access to chat room';
$string['privacy:metadata:chat_users:userid'] = 'The user ID';
$string['privacy:metadata:chat_users:version'] = 'How user accessed the chat (sockets/basic/ajax/header_js)';
$string['privacy:metadata:messages'] = 'A record of the messages sent during a chat session';
$string['privacy:metadata:messages:issystem'] = 'Whether the message is a system-generated message';
$string['privacy:metadata:messages:message'] = 'The message';
$string['privacy:metadata:messages:timestamp'] = 'The time when the message was sent.';
$string['privacy:metadata:messages:userid'] = 'The user ID of the author of the message';
$string['refreshroom'] = 'Refresh room';
$string['refreshuserlist'] = 'Refresh user list';
$string['removemessages'] = 'Remove all messages';
$string['repeatdaily'] = 'At the same time every day';
$string['repeatnone'] = 'No repeats - publish the specified time only';
$string['repeattimes'] = 'Repeat/publish session times';
$string['repeatweekly'] = 'At the same time every week';
$string['saidto'] = 'said to';
$string['savemessages'] = 'Save past sessions';
$string['seesession'] = 'See this session';
$string['search:activity'] = 'Chat - activity information';
$string['send'] = 'Send';
$string['sending'] = 'Sending';
$string['serverhost'] = 'Server name';
$string['serverip'] = 'Server ip';
$string['servermax'] = 'Max users';
$string['serverport'] = 'Server port';
$string['sessions'] = 'Chat sessions';
$string['sessionstartsin'] = 'The next chat session will start {$a} from now.';
$string['strftimemessage'] = '%H:%M';
$string['studentseereports'] = 'Everyone can view past sessions';
$string['studentseereports_help'] = 'If set to No, only users have mod/chat:readlog capability are able to see the chat logs';
$string['talk'] = 'Talk';
$string['updatemethod'] = 'Update method';
$string['updaterate'] = 'Update rate:';
$string['userlist'] = 'User list';
$string['usingchat'] = 'Using chat';
$string['usingchat_help'] = 'The chat module contains some features to make chatting a little nicer.
* Smilies - Any smiley faces (emoticons) that you can type elsewhere in Moodle can also be typed here, for example :-)
* Links - Website addresses will be turned into links automatically
* Emoting - You can start a line with "/me" or ":" to emote, for example if your name is Kim and you type ":laughs!" or "/me laughs!" then everyone will see "Kim laughs!"
* Beeps - You can send a sound to other participants by clicking the "beep" link next to their name. A useful shortcut to beep all the people in the chat at once is to type "beep all".
* HTML - If you know some HTML code, you can use it in your text to do things like insert images, play sounds or create different coloured text';
$string['viewreport'] = 'Past sessions';
+1621
View File
File diff suppressed because it is too large Load Diff
+254
View File
@@ -0,0 +1,254 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Library of functions for chat outside of the core api
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/mod/chat/lib.php');
require_once($CFG->libdir . '/portfolio/caller.php');
/**
* @package mod_chat
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class chat_portfolio_caller extends portfolio_module_caller_base {
/** @var object */
private $chat;
/** @var int Timestamp */
protected $start;
/** @var int Timestamp */
protected $end;
/** @var array Chat messages */
protected $messages = [];
/** @var bool True if participated, otherwise false. */
protected $participated;
/**
* @return array
*/
public static function expected_callbackargs() {
return array(
'id' => true,
'start' => false,
'end' => false,
);
}
/**
* @global object
*/
public function load_data() {
global $DB;
if (!$this->cm = get_coursemodule_from_id('chat', $this->id)) {
throw new portfolio_caller_exception('invalidid', 'chat');
}
$this->chat = $DB->get_record('chat', array('id' => $this->cm->instance));
$select = 'chatid = ?';
$params = array($this->chat->id);
if ($this->start && $this->end) {
$select .= ' AND timestamp >= ? AND timestamp <= ?';
$params[] = $this->start;
$params[] = $this->end;
}
$this->messages = $DB->get_records_select(
'chat_messages',
$select,
$params,
'timestamp ASC'
);
$select .= ' AND userid = ?';
$params[] = $this->user->id;
$this->participated = $DB->record_exists_select(
'chat_messages',
$select,
$params
);
}
/**
* @return array
*/
public static function base_supported_formats() {
return array(PORTFOLIO_FORMAT_PLAINHTML);
}
/**
*
*/
public function expected_time() {
return portfolio_expected_time_db(count($this->messages));
}
/**
* @return string
*/
public function get_sha1() {
$str = '';
ksort($this->messages);
foreach ($this->messages as $m) {
$str .= implode('', (array)$m);
}
return sha1($str);
}
/**
* @return bool
*/
public function check_permissions() {
$context = context_module::instance($this->cm->id);
return has_capability('mod/chat:exportsession', $context)
|| ($this->participated
&& has_capability('mod/chat:exportparticipatedsession', $context));
}
/**
* @todo Document this function
*/
public function prepare_package() {
$content = '';
$lasttime = 0;
foreach ($this->messages as $message) { // We are walking FORWARDS through messages
$m = clone $message; // grrrrrr - this causes the sha1 to change as chat_format_message changes what it's passed.
$formatmessage = chat_format_message($m, $this->cm->course, $this->user);
if (!isset($formatmessage->html)) {
continue;
}
if (empty($lasttime) || (($message->timestamp - $lasttime) > CHAT_SESSION_GAP)) {
$content .= '<hr />';
$content .= userdate($message->timestamp);
}
$content .= $formatmessage->html;
$lasttime = $message->timestamp;
}
$content = preg_replace('/\<img[^>]*\>/', '', $content);
$this->exporter->write_new_file($content, clean_filename($this->cm->name . '-session.html'), false);
}
/**
* @return string
*/
public static function display_name() {
return get_string('modulename', 'chat');
}
/**
* @global object
* @return string
*/
public function get_return_url() {
global $CFG;
return $CFG->wwwroot . '/mod/chat/report.php?id='
. $this->cm->id . ((isset($this->start)) ? '&start=' . $this->start . '&end=' . $this->end : '');
}
}
/**
* A chat event such a user entering or leaving a chat activity
*
* @package mod_chat
* @copyright 2012 Andrew Davis
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class event_message implements renderable {
/** @var string The URL of the profile of the user who caused the event */
public $senderprofile;
/** @var string The ready to display name of the user who caused the event */
public $sendername;
/** @var string Ready to display event time */
public $time;
/** @var string Event description */
public $event;
/** @var string The chat theme name */
public $theme;
/**
* event_message constructor
*
* @param string $senderprofile The URL of the profile of the user who caused the event
* @param string $sendername The ready to display name of the user who caused the event
* @param string $time Ready to display event time
* @param string $theme The chat theme name
*/
public function __construct($senderprofile, $sendername, $time, $event, $theme) {
$this->senderprofile = $senderprofile;
$this->sendername = $sendername;
$this->time = $time;
$this->event = $event;
$this->theme = $theme;
}
}
/**
* A chat message from a user
*
* @package mod_chat
* @copyright 2012 Andrew Davis
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class user_message implements renderable {
/** @var string The URL of the profile of the user sending the message */
public $senderprofile;
/** @var string The ready to display name of the user sending the message */
public $sendername;
/** @var string HTML for the avatar of the user sending the message */
public $avatar;
/** @var string Empty or a html class definition to append to the html */
public $mymessageclass;
/** @var string Ready to display message time */
public $time;
/** @var string The message */
public $message;
/** @var string The name of the chat theme to use */
public $theme;
/**
* user_message constructor
*
* @param string $senderprofile The URL of the profile of the user sending the message
* @param string $sendername The ready to display name of the user sending the message
* @param string $avatar HTML for the avatar of the user sending the message
* @param string $mymessageclass Empty or a html class definition to append to the html
* @param string $time Ready to display message time
* @param string $message The message
* @param string $theme The name of the chat theme to use
*/
public function __construct($senderprofile, $sendername, $avatar, $mymessageclass, $time, $message, $theme) {
$this->senderprofile = $senderprofile;
$this->sendername = $sendername;
$this->avatar = $avatar;
$this->mymessageclass = $mymessageclass;
$this->time = $time;
$this->message = $message;
$this->theme = $theme;
}
}
+80
View File
@@ -0,0 +1,80 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); // It must be included from a Moodle page.
}
require_once($CFG->dirroot.'/course/moodleform_mod.php');
class mod_chat_mod_form extends moodleform_mod {
/**
* Define the chat activity settings form
*/
public function definition() {
global $CFG;
$mform = $this->_form;
$mform->addElement('header', 'general', get_string('general', 'form'));
$mform->addElement('text', 'name', get_string('chatname', 'chat'), array('size' => '64'));
if (!empty($CFG->formatstringstriptags)) {
$mform->setType('name', PARAM_TEXT);
} else {
$mform->setType('name', PARAM_CLEANHTML);
}
$mform->addRule('name', null, 'required', null, 'client');
$mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
$this->standard_intro_elements(get_string('chatintro', 'chat'));
// Chat sessions.
$mform->addElement('header', 'sessionshdr', get_string('sessions', 'chat'));
$mform->addElement('date_time_selector', 'chattime', get_string('chattime', 'chat'));
$options = array();
$options[0] = get_string('donotusechattime', 'chat');
$options[1] = get_string('repeatnone', 'chat');
$options[2] = get_string('repeatdaily', 'chat');
$options[3] = get_string('repeatweekly', 'chat');
$mform->addElement('select', 'schedule', get_string('repeattimes', 'chat'), $options);
$options = array();
$options[0] = get_string('neverdeletemessages', 'chat');
$options[365] = get_string('numdays', '', 365);
$options[180] = get_string('numdays', '', 180);
$options[150] = get_string('numdays', '', 150);
$options[120] = get_string('numdays', '', 120);
$options[90] = get_string('numdays', '', 90);
$options[60] = get_string('numdays', '', 60);
$options[30] = get_string('numdays', '', 30);
$options[21] = get_string('numdays', '', 21);
$options[14] = get_string('numdays', '', 14);
$options[7] = get_string('numdays', '', 7);
$options[2] = get_string('numdays', '', 2);
$mform->addElement('select', 'keepdays', get_string('savemessages', 'chat'), $options);
$mform->addElement('selectyesno', 'studentlogs', get_string('studentseereports', 'chat'));
$mform->addHelpButton('studentlogs', 'studentseereports', 'chat');
$this->standard_coursemodule_elements();
$this->add_action_buttons();
}
}
+6
View File
@@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMid meet">
<path d="M11.3968 11.3813C11.1206 11.3813 10.8968 11.6052 10.8968 11.8813C10.8968 12.1575 11.1206 12.3813 11.3968 12.3813H18.4024C18.6785 12.3813 18.9024 12.1575 18.9024 11.8813C18.9024 11.6052 18.6785 11.3813 18.4024 11.3813H11.3968Z" fill="#212529"/>
<path d="M10.8968 13.8813C10.8968 13.6052 11.1206 13.3813 11.3968 13.3813H18.4024C18.6785 13.3813 18.9024 13.6052 18.9024 13.8813C18.9024 14.1575 18.6785 14.3813 18.4024 14.3813H11.3968C11.1206 14.3813 10.8968 14.1575 10.8968 13.8813Z" fill="#212529"/>
<path d="M11.3968 15.3813C11.1206 15.3813 10.8968 15.6052 10.8968 15.8813C10.8968 16.1575 11.1206 16.3813 11.3968 16.3813H15.427C15.7031 16.3813 15.927 16.1575 15.927 15.8813C15.927 15.6052 15.7031 15.3813 15.427 15.3813H11.3968Z" fill="#212529"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.5829 3.04627C15.571 4.0343 16.2179 5.236 16.5223 6.50307C17.7083 6.82698 18.8287 7.45472 19.7602 8.38632C22.0432 10.6692 22.5009 14.0847 21.1358 16.8221L22.1134 20.4707C22.1597 20.6433 22.1104 20.8274 21.984 20.9537C21.8577 21.08 21.6736 21.1293 21.5011 21.0831L17.8525 20.1054C15.1151 21.4705 11.6996 21.0128 9.41669 18.7299C8.42797 17.7411 7.7815 16.5398 7.47728 15.273C7.02201 15.1486 6.5763 14.9794 6.14715 14.7654L2.49856 15.743C2.32602 15.7893 2.14191 15.7399 2.0156 15.6136C1.88929 15.4873 1.83996 15.3032 1.88619 15.1307L2.86382 11.4821C1.49877 8.74468 1.95649 5.32918 4.23939 3.04627C7.09569 0.18998 11.7267 0.189979 14.5829 3.04627ZM13.8758 3.75338C14.6131 4.49059 15.1294 5.36375 15.4257 6.29189C13.2857 6.04673 11.0581 6.74487 9.41669 8.38632C7.8327 9.97031 7.12713 12.1001 7.29998 14.1703C7.02232 14.0721 6.75021 13.9538 6.48588 13.8156C6.37036 13.7385 6.22349 13.7097 6.07881 13.7484L3.07626 14.553L3.88079 11.5504C3.91956 11.4057 3.89072 11.2589 3.81365 11.1433C2.56818 8.76198 2.94664 5.75324 4.9465 3.75338C7.41227 1.28761 11.4101 1.28761 13.8758 3.75338ZM10.1238 9.09342C7.65803 11.5592 7.65803 15.557 10.1238 18.0228C12.1237 20.0226 15.1324 20.4011 17.5138 19.1556C17.6293 19.0785 17.7762 19.0497 17.9208 19.0885L20.9234 19.893L20.1189 16.8905C20.0801 16.7458 20.1089 16.5989 20.186 16.4834C21.4315 14.102 21.053 11.0933 19.0531 9.09342C16.5874 6.62766 12.5896 6.62766 10.1238 9.09342Z" fill="#212529"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

+106
View File
@@ -0,0 +1,106 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Chat module rendering methods
*
* @package mod_chat
* @copyright 2012 Andrew Davis
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Chat module renderer class
*
* @copyright 2012 Andrew Davis
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_chat_renderer extends plugin_renderer_base {
/**
* Render and event_message instance
*
* @param event_message $eventmessage The event_message instance to render
* @return string HTML representing the event_message instance
*/
protected function render_event_message(event_message $eventmessage) {
global $CFG;
if (file_exists($CFG->dirroot . '/mod/chat/gui_ajax/theme/'.$eventmessage->theme.'/config.php')) {
include($CFG->dirroot . '/mod/chat/gui_ajax/theme/'.$eventmessage->theme.'/config.php');
}
$patterns = array();
$patterns[] = '___senderprofile___';
$patterns[] = '___sender___';
$patterns[] = '___time___';
$patterns[] = '___event___';
$replacements = array();
$replacements[] = $eventmessage->senderprofile;
$replacements[] = $eventmessage->sendername;
$replacements[] = $eventmessage->time;
$replacements[] = $eventmessage->event;
return str_replace($patterns, $replacements, $chattheme_cfg->event_message);
}
/**
* Render a user message
*
* @param user_message $usermessage the user message to display
* @return string html representation of a user_message instance
*/
protected function render_user_message(user_message $usermessage) {
global $CFG;
if (file_exists($CFG->dirroot . '/mod/chat/gui_ajax/theme/'.$usermessage->theme.'/config.php')) {
include($CFG->dirroot . '/mod/chat/gui_ajax/theme/'.$usermessage->theme.'/config.php');
}
$patterns = array();
$patterns[] = '___avatar___';
$patterns[] = '___sender___';
$patterns[] = '___senderprofile___';
$patterns[] = '___time___';
$patterns[] = '___message___';
$patterns[] = '___mymessageclass___';
$replacements = array();
$replacements[] = $usermessage->avatar;
$replacements[] = $usermessage->sendername;
$replacements[] = $usermessage->senderprofile;
$replacements[] = $usermessage->time;
$replacements[] = $usermessage->message;
$replacements[] = $usermessage->mymessageclass;
$output = null;
if (!empty($chattheme_cfg->avatar) and !empty($chattheme_cfg->align)) {
if (!empty($usermessage->mymessageclass)) {
$output = str_replace($patterns, $replacements, $chattheme_cfg->user_message_right);
} else {
$output = str_replace($patterns, $replacements, $chattheme_cfg->user_message_left);
}
} else {
$output = str_replace($patterns, $replacements, $chattheme_cfg->user_message);
}
return $output;
}
}
+274
View File
@@ -0,0 +1,274 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
// This page prints reports and info about chats.
require_once('../../config.php');
require_once('lib.php');
$id = required_param('id', PARAM_INT);
$start = optional_param('start', 0, PARAM_INT); // Start of period.
$end = optional_param('end', 0, PARAM_INT); // End of period.
$deletesession = optional_param('deletesession', 0, PARAM_BOOL);
$confirmdelete = optional_param('confirmdelete', 0, PARAM_BOOL);
$showall = optional_param('show_all', 0, PARAM_BOOL);
$url = new moodle_url('/mod/chat/report.php', array('id' => $id));
if ($start !== 0) {
$url->param('start', $start);
}
if ($end !== 0) {
$url->param('end', $end);
}
if ($deletesession !== 0) {
$url->param('deletesession', $deletesession);
}
if ($confirmdelete !== 0) {
$url->param('confirmdelete', $confirmdelete);
}
$PAGE->set_url($url);
if (! $cm = get_coursemodule_from_id('chat', $id)) {
throw new \moodle_exception('invalidcoursemodule');
}
if (! $chat = $DB->get_record('chat', array('id' => $cm->instance))) {
throw new \moodle_exception('invalidcoursemodule');
}
if (! $course = $DB->get_record('course', array('id' => $chat->course))) {
throw new \moodle_exception('coursemisconf');
}
require_login($course, false, $cm);
$context = context_module::instance($cm->id);
$PAGE->set_context($context);
$PAGE->set_heading($course->fullname);
if (empty($chat->studentlogs) && !has_capability('mod/chat:readlog', $context)) {
notice(get_string('nopermissiontoseethechatlog', 'chat'));
}
$params = array(
'context' => $context,
'objectid' => $chat->id,
'other' => array(
'start' => $start,
'end' => $end
)
);
$event = \mod_chat\event\sessions_viewed::create($params);
$event->add_record_snapshot('chat', $chat);
$event->trigger();
$strchats = get_string('modulenameplural', 'chat');
$strchat = get_string('modulename', 'chat');
$strchatreport = get_string('chatreport', 'chat');
$strseesession = get_string('seesession', 'chat');
$strdeletesession = get_string('deletesession', 'chat');
$navlinks = array();
$canexportsess = has_capability('mod/chat:exportsession', $context);
$canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
$PAGE->activityheader->set_attrs([
'title' => '',
'description' => '',
'hidecompletion' => true,
'hideoverflow' => true,
]);
// Print a session if one has been specified.
if ($start and $end and !$confirmdelete) { // Show a full transcript.
$PAGE->navbar->add($strchatreport);
echo $OUTPUT->header();
// Check to see if groups are being used here.
$groupmode = groups_get_activity_groupmode($cm);
$currentgroup = groups_get_activity_group($cm, true);
groups_print_activity_menu($cm, $CFG->wwwroot . "/mod/chat/report.php?id=$cm->id");
if ($deletesession and has_capability('mod/chat:deletelog', $context)) {
echo $OUTPUT->confirm(get_string('deletesessionsure', 'chat'),
"report.php?id=$cm->id&deletesession=1&confirmdelete=1&start=$start&end=$end",
"report.php?id=$cm->id");
}
if (!$messages = chat_get_session_messages($chat->id, $currentgroup, $start, $end, 'timestamp ASC')) {
echo $OUTPUT->heading(get_string('nomessages', 'chat'));
} else {
echo '<p class="boxaligncenter">'.userdate($start).' --> '. userdate($end).'</p>';
echo $OUTPUT->box_start('center');
$participates = array();
foreach ($messages as $message) { // We are walking FORWARDS through messages.
if (!isset($participates[$message->userid])) {
$participates[$message->userid] = true;
}
$formatmessage = chat_format_message($message, $course->id, $USER);
if (isset($formatmessage->html)) {
echo $formatmessage->html;
}
}
$participatedcap = array_key_exists($USER->id, $participates)
&& has_capability('mod/chat:exportparticipatedsession', $context);
if (!empty($CFG->enableportfolios) && ($canexportsess || $participatedcap)) {
require_once($CFG->libdir . '/portfoliolib.php');
$buttonoptions = array(
'id' => $cm->id,
'start' => $start,
'end' => $end,
);
$button = new portfolio_add_button();
$button->set_callback_options('chat_portfolio_caller', $buttonoptions, 'mod_chat');
$button->render();
}
echo $OUTPUT->box_end();
}
if (!$deletesession or !has_capability('mod/chat:deletelog', $context)) {
echo $OUTPUT->continue_button("report.php?id=$cm->id");
}
echo $OUTPUT->footer();
exit;
}
// Print the Sessions display.
$PAGE->navbar->add($strchatreport);
$PAGE->set_title($strchatreport);
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('sessions', 'chat'), 2);
// Check to see if groups are being used here
if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used.
$currentgroup = groups_get_activity_group($cm, true);
groups_print_activity_menu($cm, $CFG->wwwroot . "/mod/chat/report.php?id=$cm->id");
} else {
$currentgroup = false;
}
$params = array('currentgroup' => $currentgroup, 'chatid' => $chat->id, 'start' => $start, 'end' => $end);
// If the user is allocated to a group, only show discussions with people in
// the same group, or no group.
if (!empty($currentgroup)) {
$groupselect = " AND (groupid = :currentgroup OR groupid = 0)";
} else {
$groupselect = "";
}
// Delete a session if one has been specified.
if ($deletesession and has_capability('mod/chat:deletelog', $context)
and $confirmdelete and $start and $end and confirm_sesskey()) {
$DB->delete_records_select('chat_messages', "chatid = :chatid AND timestamp >= :start AND
timestamp <= :end $groupselect", $params);
$strdeleted = get_string('deleted');
echo $OUTPUT->notification("$strdeleted: ".userdate($start).' --> '. userdate($end));
unset($deletesession);
}
// Get the messages.
if (empty($messages)) { // May have already got them above.
if (!$messages = chat_get_session_messages($chat->id, $currentgroup, 0, 0, 'timestamp DESC')) {
echo $OUTPUT->heading(get_string('nomessages', 'chat'), 3);
echo $OUTPUT->footer();
exit;
}
}
if ($showall) {
$headingstr = get_string('listing_all_sessions', 'chat') . '&nbsp;';
$headingstr .= html_writer::link("report.php?id={$cm->id}&show_all=0", get_string('list_complete_sessions', 'chat'));
echo $OUTPUT->heading($headingstr, 3);
}
// Show all the sessions.
$completesessions = 0;
echo '<div class="list-group">';
$sessions = chat_get_sessions($messages, $showall);
foreach ($sessions as $session) {
echo '<div class="list-group-item">';
echo '<p>'.userdate($session->sessionstart).' --> '. userdate($session->sessionend).'</p>';
echo $OUTPUT->box_start();
arsort($session->sessionusers);
foreach ($session->sessionusers as $sessionuser => $usermessagecount) {
if ($user = $DB->get_record('user', array('id' => $sessionuser))) {
$OUTPUT->user_picture($user, array('courseid' => $course->id));
echo '&nbsp;' . fullname($user, $canviewfullnames);
echo "&nbsp;($usermessagecount)<br />";
}
}
echo '<p align="right">';
echo "<a href=\"report.php?id=$cm->id&amp;start=$session->sessionstart&amp;end=$session->sessionend\">$strseesession</a>";
$participatedcap = (array_key_exists($USER->id, $session->sessionusers)
&& has_capability('mod/chat:exportparticipatedsession', $context));
if (!empty($CFG->enableportfolios) && ($canexportsess || $participatedcap)) {
require_once($CFG->libdir . '/portfoliolib.php');
$buttonoptions = array(
'id' => $cm->id,
'start' => $session->sessionstart,
'end' => $session->sessionend,
);
$button = new portfolio_add_button();
$button->set_callback_options('chat_portfolio_caller', $buttonoptions, 'mod_chat');
$portfoliobutton = $button->to_html(PORTFOLIO_ADD_TEXT_LINK);
if (!empty($portfoliobutton)) {
echo '<br />' . $portfoliobutton;
}
}
if (has_capability('mod/chat:deletelog', $context)) {
$deleteurl = "report.php?id=$cm->id&amp;start=$session->sessionstart&amp;end=$session->sessionend&amp;deletesession=1";
echo "<br /><a href=\"$deleteurl\">$strdeletesession</a>";
}
echo '</p>';
echo $OUTPUT->box_end();
echo '</div>';
if ($session->iscomplete) {
$completesessions++;
}
}
echo '</div>';
if (!empty($CFG->enableportfolios) && $canexportsess) {
require_once($CFG->libdir . '/portfoliolib.php');
$button = new portfolio_add_button();
$button->set_callback_options('chat_portfolio_caller', array('id' => $cm->id), 'mod_chat');
$button->render(null, get_string('addalltoportfolio', 'portfolio'));
}
if (!$showall and $completesessions == 0) {
echo html_writer::start_tag('p');
echo get_string('no_complete_sessions_found', 'chat') . '&nbsp;';
echo html_writer::link('report.php?id='.$cm->id.'&show_all=1', get_string('list_all_sessions', 'chat'));
echo html_writer::end_tag('p');
}
// Finish the page.
echo $OUTPUT->footer();
+62
View File
@@ -0,0 +1,62 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
defined('MOODLE_INTERNAL') || die;
if ($ADMIN->fulltree) {
$settings->add(new admin_setting_heading('chat_method_heading', get_string('generalconfig', 'chat'),
get_string('explaingeneralconfig', 'chat')));
$options = array();
$options['ajax'] = get_string('methodajax', 'chat');
$options['header_js'] = get_string('methodnormal', 'chat');
$options['sockets'] = get_string('methoddaemon', 'chat');
$settings->add(new admin_setting_configselect('chat_method', get_string('method', 'chat'),
get_string('configmethod', 'chat'), 'ajax', $options));
$settings->add(new admin_setting_configtext('chat_refresh_userlist', get_string('refreshuserlist', 'chat'),
get_string('configrefreshuserlist', 'chat'), 10, PARAM_INT));
$settings->add(new admin_setting_configtext('chat_old_ping', get_string('oldping', 'chat'),
get_string('configoldping', 'chat'), 35, PARAM_INT));
$settings->add(new admin_setting_heading('chat_normal_heading', get_string('methodnormal', 'chat'),
get_string('explainmethodnormal', 'chat')));
$settings->add(new admin_setting_configtext('chat_refresh_room', get_string('refreshroom', 'chat'),
get_string('configrefreshroom', 'chat'), 5, PARAM_INT));
$options = array();
$options['jsupdate'] = get_string('normalkeepalive', 'chat');
$options['jsupdated'] = get_string('normalstream', 'chat');
$settings->add(new admin_setting_configselect('chat_normal_updatemode', get_string('updatemethod', 'chat'),
get_string('confignormalupdatemode', 'chat'), 'jsupdate', $options));
$settings->add(new admin_setting_heading('chat_daemon_heading', get_string('methoddaemon', 'chat'),
get_string('explainmethoddaemon', 'chat')));
$settings->add(new admin_setting_configtext('chat_serverhost', get_string('serverhost', 'chat'),
get_string('configserverhost', 'chat'), get_host_from_url($CFG->wwwroot)));
$settings->add(new admin_setting_configtext('chat_serverip', get_string('serverip', 'chat'),
get_string('configserverip', 'chat'), '127.0.0.1'));
$settings->add(new admin_setting_configtext('chat_serverport', get_string('serverport', 'chat'),
get_string('configserverport', 'chat'), 9111, PARAM_INT));
$settings->add(new admin_setting_configtext('chat_servermax', get_string('servermax', 'chat'),
get_string('configservermax', 'chat'), 100, PARAM_INT));
}
+114
View File
@@ -0,0 +1,114 @@
/** General Styles **/
.path-mod-chat .chat-event .picture,
.path-mod-chat .chat-message .picture {
width: 40px;
}
.path-mod-chat .chat-event .text {
text-align: left;
}
.path-mod-chat #messages-list,
.path-mod-chat #users-list {
list-style-type: none;
padding: 0;
margin: 0;
}
.path-mod-chat #chat-header {
overflow: hidden;
}
.path-mod-chat #chat-input-area table.generaltable td.cell {
padding: 1px;
}
/** shrink the text box so the theme link is always accessible */
@media all and (max-device-width: 320px) {
.path-mod-chat #input-message {
width: 150px;
}
}
@media all and (min-device-width: 321px) and (max-device-width: 640px) {
.path-mod-chat #input-message {
width: 175px;
}
}
/** styles for view.php **/
#page-mod-chat-view .chatcurrentusers .chatuserdetails {
vertical-align: middle;
}
/** Styles for basic chat **/
#page-mod-chat-gui_basic #participants ul {
margin: 0;
padding: 0;
list-style-type: none;
}
#page-mod-chat-gui_basic #participants ul li {
list-style-type: none;
display: inline;
margin-right: 10px;
}
#page-mod-chat-gui_basic #participants ul li .userinfo {
display: inline;
}
#page-mod-chat-gui_basic #messages {
padding: 0;
margin: 0;
}
#page-mod-chat-gui_basic #messages dl {
padding: 0;
margin: 6px 0;
}
#page-mod-chat-gui_basic #messages dt {
margin-left: 0;
margin-right: 5px;
padding: 0;
display: inline;
}
#page-mod-chat-gui_basic #messages dd {
padding: 0;
margin: 0;
}
/** Styles for header **/
#page-mod-chat-gui_header_js-jsupdate .chat-event,
#page-mod-chat-gui_header_js-jsupdate .chat-message {
width: 100%;
}
/** YUI Overrides **/
.path-mod-chat .yui-layout-unit-top {
background: #ffe39d;
}
.path-mod-chat .yui-layout-unit-right {
background: #fff;
}
.path-mod-chat .yui-layout-unit-bottom {
background: #fff;
}
.path-mod-chat .yui-layout .yui-layout-hd {
border: 0;
}
.path-mod-chat .yui-layout .yui-layout-unit div.yui-layout-bd {
border: 0;
background: transparent;
}
.path-mod-chat .yui-layout .yui-layout-unit div.yui-layout-unit-right {
background: white;
}
@@ -0,0 +1,64 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_chat\backup;
use core_external\external_api;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . "/phpunit/classes/restore_date_testcase.php");
/**
* Restore date tests.
*
* @package mod_chat
* @copyright 2017 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class restore_date_test extends \restore_date_testcase {
public function test_restore_dates(): void {
global $DB;
list($course, $chat) = $this->create_course_and_module('chat');
$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);
$message = $DB->get_record('chat_messages', ['id' => $result['messageid']]);
$timestamp = 1000;
$DB->set_field('chat_messages', 'timestamp', $timestamp);
// Do backup and restore.
$newcourseid = $this->backup_and_restore($course);
$newchat = $DB->get_record('chat', ['course' => $newcourseid]);
$this->assertFieldsNotRolledForward($chat, $newchat, ['timemodified']);
$props = ['chattime'];
$this->assertFieldsRolledForward($chat, $newchat, $props);
$newmessages = $DB->get_records('chat_messages', ['chatid' => $newchat->id]);
foreach ($newmessages as $message) {
$this->assertEquals($timestamp, $message->timestamp);
}
}
}
+76
View File
@@ -0,0 +1,76 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Steps definitions related to mod_chat.
*
* @package mod_chat
* @category test
* @copyright 2021 Dongsheng Cai
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
/**
* Steps definitions related to mod_chat.
*
*/
class behat_mod_chat extends behat_base {
/**
* Convert page names to URLs for steps like 'When I am on the "[identifier]" "[page type]" page'.
*
* Recognised page names are:
* | pagetype | name meaning | description |
* | View | Chat name | The chat info page (view.php) |
*
* @param string $type identifies which type of page this is, e.g. 'View'.
* @param string $name chat instance name
* @return moodle_url the corresponding URL.
* @throws Exception with a meaningful error message if the specified page cannot be found.
*/
protected function resolve_page_instance_url(string $type, string $name): moodle_url {
switch (strtolower($type)) {
case 'view':
$cm = $this->get_cm_by_chat_name($name);
return new moodle_url('/mod/chat/view.php', ['id' => $cm->id]);
default:
throw new Exception('Unrecognised chat page type "' . $type . '."');
}
}
/**
* Get a chat by name.
*
* @param string $name chat name.
* @return stdClass the corresponding DB row.
*/
protected function get_chat_by_name(string $name): stdClass {
global $DB;
return $DB->get_record('chat', ['name' => $name], '*', MUST_EXIST);
}
/**
* Get a chat coursemodule object from the name.
*
* @param string $name chat name.
* @return stdClass cm from get_coursemodule_from_instance.
*/
protected function get_cm_by_chat_name(string $name): stdClass {
$chat = $this->get_chat_by_name($name);
return get_coursemodule_from_instance('chat', $chat->id, $chat->course);
}
}
@@ -0,0 +1,56 @@
@mod @mod_chat @core_completion
Feature: View activity completion information in the chat activity
In order to have visibility of chat completion requirements
As a student
I need to be able to view my chat completion progress
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Vinnie | Student1 | student1@example.com |
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | category | enablecompletion |
| Course 1 | C1 | 0 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
And I enable "chat" "mod" plugin
Scenario: View automatic completion items
Given I log in as "teacher1"
And the following "activity" exists:
| activity | chat |
| course | C1 |
| name | Music history |
| section | 1 |
| completion | 2 |
| completionview | 1 |
And I am on "Course 1" course homepage
# Teacher view.
And I am on the "Music history" Activity page
And "Music history" should have the "View" completion condition
And I log out
# Student view.
And I am on the "Music history" Activity page logged in as student1
Then the "View" completion condition of "Music history" is displayed as "done"
@javascript
Scenario: Use manual completion
Given I log in as "teacher1"
And the following "activity" exists:
| activity | chat |
| course | C1 |
| name | Music history |
| section | 1 |
| completion | 1 |
And I am on "Course 1" course homepage
# Teacher view.
And "Music history" should have the "Mark as done" completion condition
And I log out
# Student view.
And I am on the "Music history" Activity page logged in as student1
Then the manual completion button of "Music history" is displayed as "Mark as done"
And I toggle the manual completion state of "Music history"
And the manual completion button of "Music history" is displayed as "Done"
@@ -0,0 +1,36 @@
@mod @mod_chat
Feature: Chat calendar entries
In order to notify students of upcoming chat sessons
As a teacher
I need to create a chat activity and publish the event times
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Tina | Teacher1 | teacher1@example.com |
| student1 | Sam | Student1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And I enable "chat" "mod" plugin
Scenario Outline: Create a chat activity with repeated chat times set
# Create an activity with repeated chat times
Given the following "activities" exist:
| activity | course | name | schedule |
| chat | C1 | Chat 1 | <scheduleset> |
And I log in as "teacher1"
# Confirm Chat activity visibility based on schedule
When I am viewing calendar in "upcoming" view
Then I <chatvisibility> see "Chat 1"
Examples:
| scheduleset | chatvisibility |
| 0 | should not |
| 1 | should |
| 2 | should |
| 3 | should |
@@ -0,0 +1,55 @@
@mod @mod_chat
Feature: Chat reset
In order to reuse past chat activities
As a teacher
I need to remove all previous data.
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Tina | Teacher1 | teacher1@example.com |
| student1 | Sam | Student1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And I enable "chat" "mod" plugin
And the following "activities" exist:
| activity | name | Description | course | idnumber |
| chat | Test chat name | Test chat description | C1 | chat1 |
Scenario: Use course reset to update chat start date
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| startdate[day] | 1 |
| startdate[month] | January |
| startdate[year] | 2020 |
And I press "Save and display"
And I follow "Test chat name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| chattime[day] | 1 |
| chattime[month] | January |
| chattime[year] | 2020 |
| chattime[hour] | 12 |
| chattime[minute] | 00 |
And I press "Save and display"
And I am on the "Course 1" "reset" page
And I set the following fields to these values:
| reset_start_date[enabled] | 1 |
| reset_start_date[day] | 1 |
| reset_start_date[month] | January |
| reset_start_date[year] | 2030 |
And I press "Reset course"
And I should see "Date changed" in the "Chats" "table_row"
And I press "Continue"
Then I am on "Course 1" course homepage
And I follow "Test chat name"
And I navigate to "Settings" in current page administration
And I expand all fieldsets
And the "chattime[year]" select box should contain "2030"
@@ -0,0 +1,61 @@
@mod @mod_chat
Feature: Chat with my group
In order to chat with my group
As a student
I want to be able to see or select by group in the Chat activity
Background:
And the following "courses" exist:
| fullname | shortname |
| Test Course 1 | C1 |
And the following "groups" exist:
| name | course | idnumber | participation |
| Group 1 | C1 | G1 | 1 |
| Group 2 | C1 | G2 | 1 |
| Group 3 | C1 | G3 | 0 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | TeacherG1 | 1 | teacher1@example.com |
| user1 | User1G1 | 1 | user1@example.com |
| user2 | User2G2 | 2 | user2@example.com |
| user3 | User3None | 3 | user3@example.com |
| user4 | User4NPgroup | 4 | user4@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| user1 | C1 | student |
| user2 | C1 | student |
| user3 | C1 | student |
| user4 | C1 | student |
And the following "group members" exist:
| user | group |
| teacher1 | G1 |
| user1 | G1 |
| user2 | G2 |
| user4 | G3 |
And I enable "chat" "mod" plugin
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode |
| chat | Separate Chat | Chat with separate groups | C1 | chat1 | 1 |
| chat | Visible Chat | Chat with visible groups | C1 | chat2 | 2 |
Scenario Outline: Users should see their own participation groups in "separate groups" mode, and all
participation groups in "visible groups" mode.
Given I am on the "<chat>" "chat activity" page logged in as "<user>"
Then I <all> "All participants"
And I <G1> "Group 1"
And I <G2> "Group 2"
And I should not see "Group 3"
Examples:
| chat | user | all | G1 | G2 |
| chat1 | teacher1 | should see | should see | should see |
| chat1 | user1 | should not see | should see | should not see |
| chat1 | user2 | should not see | should not see | should see |
| chat1 | user3 | should see | should not see | should not see |
| chat1 | user4 | should see | should not see | should not see |
| chat2 | teacher1 | should see | should see | should see |
| chat2 | user1 | should see | should see | should see |
| chat2 | user2 | should see | should see | should see |
| chat2 | user3 | should see | should see | should see |
| chat2 | user4 | should see | should see | should see |
@@ -0,0 +1,49 @@
@mod @mod_chat
Feature: Chat with no calendar capabilites
In order to allow work effectively
As a teacher
I need to be able to create chats even when I cannot edit calendar events
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And I enable "chat" "mod" plugin
And the following "activity" exists:
| activity | chat |
| course | C1 |
| idnumber | 0001 |
| name | Test chat name |
| intro | Test chat description |
| section | 1 |
And I log in as "admin"
And I am on the "Course 1" "permissions" page
And I override the system permissions of "Teacher" role with:
| capability | permission |
| moodle/calendar:manageentries | Prohibit |
And I am on "Course 1" course homepage
And I follow "Test chat name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Repeat/publish session times | No repeats - publish the specified time only |
| id_chattime_day | 1 |
| id_chattime_month | 1 |
| id_chattime_year | 2017 |
And I press "Save and return to course"
And I log out
Scenario: Editing a chat
When I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I follow "Test chat name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| id_chattime_year | 2018 |
And I press "Save and return to course"
Then I should see "Test chat name"
@@ -0,0 +1,48 @@
@mod @mod_chat @javascript
Feature: View past chat sessions
In order for students to view past chat sessions
As a teacher
I need to be able to change the mod/chat:readlog permission for students
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | One | teacher1@example.com |
| student1 | Student | One | student1@example.com |
And the following "course" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And I enable "chat" "mod" plugin
Scenario Outline: View past chat sessions
# Display or hide past chat session based on example data
Given the following "activities" exist:
| activity | course | name | studentlogs |
| chat | C1 | Chat 1 | <studentlogvalue> |
And I am on the "Chat 1" "chat activity" page logged in as teacher1
# Display or hide past chat session by default based on mod/chat:readlog setting
And the following "role capability" exists:
| role | student |
| mod/chat:readlog | <readpermission> |
# Enter chat activity to create a session
And I click on "Enter the chat" "link"
# Close chat window
When I close all opened windows
And I reload the page
# Confirm that past chat sessions is always visible for teacher
Then I should see "Past sessions"
# Confirm past chat sessions visibility for student based on settings
And I am on the "Chat 1" "chat activity" page logged in as student1
And I <sessionvisibility> see "Past sessions"
# Regardless of studentlogvalue value if readpermission is allowed, then Past sessions will be visible for students
Examples:
| studentlogvalue | readpermission | sessionvisibility |
| 0 | allow | should |
| 1 | allow | should |
| 0 | prohibit | should not |
| 1 | prohibit | should |
+137
View File
@@ -0,0 +1,137 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace mod_chat;
use advanced_testcase;
use cm_info;
use core\activity_dates;
/**
* Class for unit testing mod_chat\dates.
*
* @package mod_chat
* @category test
* @copyright 2021 Dongsheng Cai
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class dates_test extends advanced_testcase {
/**
* Setup testcase.
*/
public function setUp(): void {
// Chat module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('chat', 1);
}
/**
* Data provider for get_dates_for_module().
* @return array[]
*/
public static function get_dates_for_module_provider(): array {
global $CFG;
require_once($CFG->dirroot . '/mod/chat/lib.php');
$now = time();
$past = $now - DAYSECS;
$future = $now + DAYSECS;
$dailynextchattime = $past + 2 * DAYSECS;
$weeklynextchattime = $past + 7 * DAYSECS;
$label = get_string('nextchattime', 'mod_chat');
return [
'chattime in the past (no schedule)' => [
$past, CHAT_SCHEDULE_NONE, []
],
'chattime in the past (single schedule)' => [
$past, CHAT_SCHEDULE_SINGLE, []
],
'chattime in the future' => [
$future, CHAT_SCHEDULE_SINGLE, [
[
'label' => $label,
'timestamp' => $future,
'dataid' => 'chattime',
],
]
],
'future chattime weekly' => [
$future, CHAT_SCHEDULE_WEEKLY, [
[
'label' => $label,
'timestamp' => $future,
'dataid' => 'chattime',
]
]
],
'future chattime daily' => [
$future, CHAT_SCHEDULE_DAILY, [
[
'label' => $label,
'timestamp' => $future,
'dataid' => 'chattime',
]
]
],
'past chattime daily' => [
$past, CHAT_SCHEDULE_DAILY, [
[
'label' => $label,
'timestamp' => $dailynextchattime,
'dataid' => 'chattime',
],
]
],
'past chattime weekly' => [
$past, CHAT_SCHEDULE_WEEKLY, [
[
'label' => $label,
'timestamp' => $weeklynextchattime,
'dataid' => 'chattime',
],
]
],
];
}
/**
* Test for get_dates_for_module().
*
* @dataProvider get_dates_for_module_provider
* @param int|null $chattime
* @param int|null $schedule
* @param array $expected The expected value of calling get_dates_for_module()
*/
public function test_get_dates_for_module(?int $chattime, ?int $schedule, array $expected): void {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$user = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->enrol_user($user->id, $course->id);
$chat = ['course' => $course->id];
$chat['chattime'] = $chattime;
$chat['schedule'] = $schedule;
$modchat = $this->getDataGenerator()->create_module('chat', $chat);
$this->setUser($user);
$cm = get_coursemodule_from_instance('chat', $modchat->id);
$cminfo = cm_info::create($cm);
$dates = activity_dates::get_dates_for_module($cminfo, (int) $user->id);
$this->assertEquals($expected, $dates);
}
}
+184
View File
@@ -0,0 +1,184 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Events tests.
*
* @package mod_chat
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\event;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/chat/lib.php');
/**
* Events tests class.
*
* @package mod_chat
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class events_test extends \advanced_testcase {
/**
* Setup testcase.
*/
public function setUp(): void {
// Chat module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('chat', 1);
}
public function test_message_sent(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id));
$cm = $DB->get_record('course_modules', array('id' => $chat->cmid));
// Logging in first user to the chat.
$this->setUser($user1->id);
$sid1 = chat_login_user($chat->id, 'ajax', 0, $course);
// Logging in second user to the chat.
$this->setUser($user2->id);
$sid2 = chat_login_user($chat->id, 'ajax', 0, $course);
// Getting the chatuser record.
$chatuser1 = $DB->get_record('chat_users', array('sid' => $sid1));
$chatuser2 = $DB->get_record('chat_users', array('sid' => $sid2));
$sink = $this->redirectEvents();
// Send a messaging from the first user. We pass the CM to chat_send_chatmessage() this time.
// This ensures that the event triggered when sending a message is filled with the correct information.
$this->setUser($user1->id);
$messageid = chat_send_chatmessage($chatuser1, 'Hello!', false, $cm);
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
$this->assertInstanceOf('\mod_chat\event\message_sent', $event);
$this->assertEquals($messageid, $event->objectid);
$this->assertEquals($user1->id, $event->relateduserid);
$this->assertEquals($user1->id, $event->userid);
// Send a messaging from the first user. We DO NOT pass the CM to chat_send_chatmessage() this time.
// This ensures that the event triggered when sending a message is filled with the correct information.
$sink->clear();
$this->setUser($user2->id);
$messageid = chat_send_chatmessage($chatuser2, 'Hello!');
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
$this->assertInstanceOf('\mod_chat\event\message_sent', $event);
$this->assertEquals($messageid, $event->objectid);
$this->assertEquals($user2->id, $event->relateduserid);
$this->assertEquals($user2->id, $event->userid);
// Sending a message from the system should not trigger any event.
$sink->clear();
$this->setAdminUser();
chat_send_chatmessage($chatuser1, 'enter', true);
$this->assertEquals(0, $sink->count());
$sink->close();
}
public function test_sessions_viewed(): void {
global $USER;
$this->resetAfterTest();
// Not much can be tested here as the event is only triggered on a page load,
// let's just check that the event contains the expected basic information.
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id));
$params = array(
'context' => \context_module::instance($chat->cmid),
'objectid' => $chat->id,
'other' => array(
'start' => 1234,
'end' => 5678
)
);
$event = \mod_chat\event\sessions_viewed::create($params);
$event->add_record_snapshot('chat', $chat);
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$event = reset($events);
$this->assertInstanceOf('\mod_chat\event\sessions_viewed', $event);
$this->assertEquals($USER->id, $event->userid);
$this->assertEquals(\context_module::instance($chat->cmid), $event->get_context());
$this->assertEquals(1234, $event->other['start']);
$this->assertEquals(5678, $event->other['end']);
$this->assertEquals($chat->id, $event->objectid);
$this->assertEquals($chat, $event->get_record_snapshot('chat', $chat->id));
}
public function test_course_module_instance_list_viewed(): void {
global $USER;
$this->resetAfterTest();
// Not much can be tested here as the event is only triggered on a page load,
// let's just check that the event contains the expected basic information.
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$params = array(
'context' => \context_course::instance($course->id)
);
$event = \mod_chat\event\course_module_instance_list_viewed::create($params);
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$event = reset($events);
$this->assertInstanceOf('\mod_chat\event\course_module_instance_list_viewed', $event);
$this->assertEquals($USER->id, $event->userid);
$this->assertEquals(\context_course::instance($course->id), $event->get_context());
}
public function test_course_module_viewed(): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id));
$cm = get_coursemodule_from_instance('chat', $chat->id);
$context = \context_module::instance($cm->id);
$params = array(
'objectid' => $chat->id,
'context' => $context
);
$event = \mod_chat\event\course_module_viewed::create($params);
$event->add_record_snapshot('chat', $chat);
$event->trigger();
$url = new \moodle_url('/mod/chat/view.php', array('id' => $cm->id));
$this->assertEquals($url, $event->get_url());
$event->get_name();
}
}
+139
View File
@@ -0,0 +1,139 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Tests for external function mod_chat_view_sessions.
*
* @package mod_chat
* @category external
* @copyright 2022 Rodrigo Mady <rodrigo.mady@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 4.3
*/
namespace mod_chat\external;
use externallib_advanced_testcase;
use moodle_exception;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
/**
* Test Class for external function mod_chat_view_sessions.
*
* @package mod_chat
* @category external
* @copyright 2023 Rodrigo Mady <rodrigo.mady@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 4.3
* @coversDefaultClass \mod_chat\external\view_sessions
*/
class view_sessions_test extends externallib_advanced_testcase {
/**
* Prepare the test.
*
* @return array
*/
private function prepare_test_data(): array {
global $DB;
$this->resetAfterTest(true);
// Chat module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('chat', 1);
$course = $this->getDataGenerator()->create_course();
$student1 = $this->getDataGenerator()->create_and_enrol($course);
$chat = $this->getDataGenerator()->create_module('chat', ['course' => $course->id]);
$context = \context_module::instance($chat->cmid);
$studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student']);
assign_capability('mod/chat:readlog', CAP_ALLOW, $studentroleid, $context, true);
$this->setUser($student1);
return [
'chat' => $chat,
];
}
/**
* Helper to call view_sessions WS function.
*
* @param int $cmid
* @param int $sessionstart
* @param int $sessionend
* @return array
*/
protected function view_sessions(int $cmid, int $sessionstart = 0, int $sessionend = 0): array {
$result = view_sessions::execute($cmid, $sessionstart, $sessionend);
return \core_external\external_api::clean_returnvalue(view_sessions::execute_returns(), $result);
}
/**
* Test for webservice view sessions.
* @covers ::execute
*/
public function test_view_sessions(): void {
$data = $this->prepare_test_data();
$result = $this->view_sessions($data['chat']->cmid);
$this->assertArrayHasKey('status', $result);
$this->assertArrayHasKey('warnings', $result);
$this->assertTrue($result['status']);
}
/**
* Test for webservice view sessions without capability.
* @covers ::execute
*/
public function test_view_sessions_without_capability(): void {
global $DB;
$data = $this->prepare_test_data();
$context = \context_module::instance($data['chat']->cmid);
$studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student']);
assign_capability('mod/chat:readlog', CAP_PROHIBIT, $studentroleid, $context, true);
$result = $this->view_sessions($data['chat']->cmid);
$this->assertArrayHasKey('status', $result);
$this->assertArrayHasKey('warnings', $result);
$this->assertFalse($result['status']);
$this->assertEquals(get_string('nopermissiontoseethechatlog', 'chat'), $result['warnings'][0]['message']);
}
/**
* Test for webservice view sessions with start and end dates.
* @covers ::execute
*/
public function test_view_sessions_with_start_end_dates(): void {
$data = $this->prepare_test_data();
$result = $this->view_sessions($data['chat']->cmid, strtotime('today'), strtotime('tomorrow'));
$this->assertArrayHasKey('status', $result);
$this->assertArrayHasKey('warnings', $result);
$this->assertTrue($result['status']);
}
/**
* Test execute with no valid instance of cmid.
* @covers ::execute
*/
public function test_view_sessions_no_instance(): void {
$this->expectException(moodle_exception::class);
$this->view_sessions(1234);
}
}
+501
View File
@@ -0,0 +1,501 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_chat;
use core_external\external_api;
use externallib_advanced_testcase;
use mod_chat_external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
/**
* External mod_chat functions unit tests
*
* @package mod_chat
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
class externallib_test extends externallib_advanced_testcase {
/**
* Setup testcase.
*/
public function setUp(): void {
// Chat module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('chat', 1);
}
/**
* Test login user
*/
public function test_login_user(): void {
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);
$result = mod_chat_external::login_user($chat->id);
$result = external_api::clean_returnvalue(mod_chat_external::login_user_returns(), $result);
// Test session started.
$sid = $DB->get_field('chat_users', 'sid', array('userid' => $user->id, 'chatid' => $chat->id));
$this->assertEquals($result['chatsid'], $sid);
}
/**
* Test get chat users
*/
public function test_get_chat_users(): void {
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();
$this->setUser($user1);
$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);
$result = mod_chat_external::login_user($chat->id);
$result = external_api::clean_returnvalue(mod_chat_external::login_user_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);
// Get users.
$result = mod_chat_external::get_chat_users($result['chatsid']);
$result = external_api::clean_returnvalue(mod_chat_external::get_chat_users_returns(), $result);
// Check correct users.
$this->assertCount(2, $result['users']);
$found = 0;
foreach ($result['users'] as $user) {
if ($user['id'] == $user1->id or $user['id'] == $user2->id) {
$found++;
}
}
$this->assertEquals(2, $found);
}
/**
* Test send and get chat messages
*/
public function test_send_get_chat_message(): void {
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);
$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);
// Test messages received.
$result = mod_chat_external::get_chat_latest_messages($chatsid, 0);
$result = external_api::clean_returnvalue(mod_chat_external::get_chat_latest_messages_returns(), $result);
foreach ($result['messages'] as $message) {
// Ommit system messages, like user just joined in.
if ($message['system']) {
continue;
}
$this->assertEquals('hello!', $message['message']);
}
}
/**
* Test view_chat
*/
public function test_view_chat(): void {
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));
$context = \context_module::instance($chat->cmid);
$cm = get_coursemodule_from_instance('chat', $chat->id);
// Test invalid instance id.
try {
mod_chat_external::view_chat(0);
$this->fail('Exception expected due to invalid mod_chat instance id.');
} catch (\moodle_exception $e) {
$this->assertEquals('invalidrecord', $e->errorcode);
}
// Test not-enrolled user.
$user = self::getDataGenerator()->create_user();
$this->setUser($user);
try {
mod_chat_external::view_chat($chat->id);
$this->fail('Exception expected due to not enrolled user.');
} catch (\moodle_exception $e) {
$this->assertEquals('requireloginerror', $e->errorcode);
}
// Test user with full capabilities.
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
// Trigger and capture the event.
$sink = $this->redirectEvents();
$result = mod_chat_external::view_chat($chat->id);
$result = external_api::clean_returnvalue(mod_chat_external::view_chat_returns(), $result);
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = array_shift($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_chat\event\course_module_viewed', $event);
$this->assertEquals($context, $event->get_context());
$moodlechat = new \moodle_url('/mod/chat/view.php', array('id' => $cm->id));
$this->assertEquals($moodlechat, $event->get_url());
$this->assertEventContextNotUsed($event);
$this->assertNotEmpty($event->get_name());
// Test user with no capabilities.
// We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
assign_capability('mod/chat:chat', CAP_PROHIBIT, $studentrole->id, $context->id);
accesslib_clear_all_caches_for_unit_testing();
try {
mod_chat_external::view_chat($chat->id);
$this->fail('Exception expected due to missing capability.');
} catch (\moodle_exception $e) {
$this->assertEquals('nopermissions', $e->errorcode);
}
}
/**
* Test get_chats_by_courses
*/
public function test_get_chats_by_courses(): void {
global $DB, $CFG;
$this->resetAfterTest(true);
$this->setAdminUser();
// Set global chat method.
$CFG->chat_method = 'header_js';
$course1 = self::getDataGenerator()->create_course();
$chatoptions1 = array(
'course' => $course1->id,
'name' => 'First Chat'
);
$chat1 = self::getDataGenerator()->create_module('chat', $chatoptions1);
$course2 = self::getDataGenerator()->create_course();
$chatoptions2 = array(
'course' => $course2->id,
'name' => 'Second Chat'
);
$chat2 = self::getDataGenerator()->create_module('chat', $chatoptions2);
$student1 = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
// Enroll Student1 in Course1.
self::getDataGenerator()->enrol_user($student1->id, $course1->id, $studentrole->id);
$this->setUser($student1);
$chats = mod_chat_external::get_chats_by_courses();
// We need to execute the return values cleaning process to simulate the web service server.
$chats = external_api::clean_returnvalue(mod_chat_external::get_chats_by_courses_returns(), $chats);
$this->assertCount(1, $chats['chats']);
$this->assertEquals('First Chat', $chats['chats'][0]['name']);
// We see 12 fields.
$this->assertCount(13, $chats['chats'][0]);
// As Student you cannot see some chat properties like 'section'.
$this->assertFalse(isset($chats['chats'][0]['section']));
// Student1 is not enrolled in course2. The webservice will return a warning!
$chats = mod_chat_external::get_chats_by_courses(array($course2->id));
// We need to execute the return values cleaning process to simulate the web service server.
$chats = external_api::clean_returnvalue(mod_chat_external::get_chats_by_courses_returns(), $chats);
$this->assertCount(0, $chats['chats']);
$this->assertEquals(1, $chats['warnings'][0]['warningcode']);
// Now as admin.
$this->setAdminUser();
// As Admin we can see this chat.
$chats = mod_chat_external::get_chats_by_courses(array($course2->id));
// We need to execute the return values cleaning process to simulate the web service server.
$chats = external_api::clean_returnvalue(mod_chat_external::get_chats_by_courses_returns(), $chats);
$this->assertCount(1, $chats['chats']);
$this->assertEquals('Second Chat', $chats['chats'][0]['name']);
$this->assertEquals('header_js', $chats['chats'][0]['chatmethod']);
// We see 17 fields.
$this->assertCount(18, $chats['chats'][0]);
// As an Admin you can see some chat properties like 'section'.
$this->assertEquals(0, $chats['chats'][0]['section']);
// Enrol student in the second course.
self::getDataGenerator()->enrol_user($student1->id, $course2->id, $studentrole->id);
$this->setUser($student1);
$chats = mod_chat_external::get_chats_by_courses();
$chats = external_api::clean_returnvalue(mod_chat_external::get_chats_by_courses_returns(), $chats);
$this->assertCount(2, $chats['chats']);
}
/**
* Test get_sessions_empty_chat
*/
public function test_get_sessions_empty_chat(): void {
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(): void {
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(): void {
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(): void {
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.
// The session started when user1 entered the chat.
$this->assertEquals($timenow - HOURSECS, $result['sessions'][0]['sessionstart']);
$this->assertEmpty($result['warnings']);
}
/**
* Test get_session_messages
*/
public function test_get_session_messages(): void {
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 send a few messages.
$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'];
mod_chat_external::send_chat_message($chatsid, 'hello!');
mod_chat_external::send_chat_message($chatsid, 'bye bye!');
$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'];
mod_chat_external::send_chat_message($chatsid, 'greetings!');
// 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.
$sessionstart = $result['sessions'][0]['sessionstart'];
$sessionend = $result['sessions'][0]['sessionend'];
$result = mod_chat_external::get_session_messages($chat->id, $sessionstart, $sessionend);
$result = external_api::clean_returnvalue(mod_chat_external::get_session_messages_returns(), $result);
$this->assertCount(5, $result['messages']); // 2 system + 3 personal messages.
$found = 0;
foreach ($result['messages'] as $message) {
if (!$message['issystem']) {
if ($message['userid'] == $user1->id) {
if ($message['message'] != 'hello!') {
$this->assertEquals('bye bye!', $message['message']);
$found++;
}
} else {
$this->assertEquals($user2->id, $message['userid']);
$this->assertEquals('greetings!', $message['message']);
$found++;
}
}
}
$this->assertEquals(2, $found);
}
}
+163
View File
@@ -0,0 +1,163 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_chat;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/chat/lib.php');
/**
* Tests for format_message.
*
* @package mod_chat
* @copyright 2016 Andrew NIcols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_message_test extends \advanced_testcase {
const USER_CURRENT = 1;
const USER_OTHER = 2;
public function chat_format_message_manually_provider() {
$dateregexp = '\d{2}:\d{2}';
return [
'Beep everyone' => [
'message' => 'beep all',
'issystem' => false,
'willreturn' => true,
'expecttext' => "/^{$dateregexp}: " . get_string('messagebeepseveryone', 'chat', '__CURRENTUSER__') . ': /',
'refreshusers' => false,
'beep' => true,
],
'Beep the current user' => [
'message' => 'beep __CURRENTUSER__',
'issystem' => false,
'willreturn' => true,
'expecttext' => "/^{$dateregexp}: " . get_string('messagebeepsyou', 'chat', '__CURRENTUSER__') . ': /',
'refreshusers' => false,
'beep' => true,
],
'Beep another user' => [
'message' => 'beep __OTHERUSER__',
'issystem' => false,
'willreturn' => false,
'expecttext' => null,
'refreshusers' => null,
'beep' => null,
],
'Malformed beep' => [
'message' => 'beep',
'issystem' => false,
'willreturn' => true,
'expecttext' => "/^{$dateregexp} __CURRENTUSER_FIRST__: beep$/",
'refreshusers' => false,
'beep' => false,
],
'/me says' => [
'message' => '/me writes a test',
'issystem' => false,
'willreturn' => true,
'expecttext' => "/^{$dateregexp}: \*\*\* __CURRENTUSER_FIRST__ writes a test$/",
'refreshusers' => false,
'beep' => false,
],
'Invalid command' => [
'message' => '/help',
'issystem' => false,
'willreturn' => true,
'expecttext' => "/^{$dateregexp} __CURRENTUSER_FIRST__: \/help$/",
'refreshusers' => false,
'beep' => false,
],
'To user' => [
'message' => 'To Bernard:I love tests',
'issystem' => false,
'willreturn' => true,
'expecttext' => "/^{$dateregexp}: __CURRENTUSER_FIRST__ " . get_string('saidto', 'chat') . " Bernard: I love tests$/",
'refreshusers' => false,
'beep' => false,
],
'To user trimmed' => [
'message' => 'To Bernard: I love tests',
'issystem' => false,
'willreturn' => true,
'expecttext' => "/^{$dateregexp}: __CURRENTUSER_FIRST__ " . get_string('saidto', 'chat') . " Bernard: I love tests$/",
'refreshusers' => false,
'beep' => false,
],
'System: enter' => [
'message' => 'enter',
'issystem' => true,
'willreturn' => true,
'expecttext' => "/^{$dateregexp}: " . get_string('messageenter', 'chat', '__CURRENTUSER__') . "$/",
'refreshusers' => true,
'beep' => false,
],
'System: exit' => [
'message' => 'exit',
'issystem' => true,
'willreturn' => true,
'expecttext' => "/^{$dateregexp}: " . get_string('messageexit', 'chat', '__CURRENTUSER__') . "$/",
'refreshusers' => true,
'beep' => false,
],
];
}
/**
* @dataProvider chat_format_message_manually_provider
*/
public function test_chat_format_message_manually($messagetext, $issystem, $willreturn,
$expecttext, $refreshusers, $expectbeep): void {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$currentuser = $this->getDataGenerator()->create_user();
$this->setUser($currentuser);
$otheruser = $this->getDataGenerator()->create_user();
// Replace the message texts.
// These can't be done in the provider because it runs before the
// test starts.
$messagetext = str_replace('__CURRENTUSER__', $currentuser->id, $messagetext);
$messagetext = str_replace('__OTHERUSER__', $otheruser->id, $messagetext);
$message = (object) [
'message' => $messagetext,
'timestamp' => time(),
'issystem' => $issystem,
];
$result = chat_format_message_manually($message, $course->id, $currentuser, $currentuser);
if (!$willreturn) {
$this->assertFalse($result);
} else {
$this->assertNotFalse($result);
if (!empty($expecttext)) {
$expecttext = str_replace('__CURRENTUSER__', fullname($currentuser), $expecttext);
$expecttext = str_replace('__CURRENTUSER_FIRST__', $currentuser->firstname, $expecttext);
$this->assertMatchesRegularExpression($expecttext, $result->text);
}
$this->assertEquals($refreshusers, $result->refreshusers);
$this->assertEquals($expectbeep, $result->beep);
}
}
}
+75
View File
@@ -0,0 +1,75 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* mod_chat data generator.
*
* @package core
* @category test
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* mod_chat data generator class.
*
* @package core
* @category test
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_chat_generator extends testing_module_generator {
/**
* @var int keep track of how many messages have been created.
*/
protected $messagecount = 0;
/**
* To be called from data reset code only,
* do not use in tests.
* @return void
*/
public function reset() {
$this->messagecount = 0;
parent::reset();
}
public function create_instance($record = null, array $options = null) {
$record = (object)(array)$record;
if (!isset($record->keepdays)) {
$record->keepdays = 0;
}
if (!isset($record->studentlogs)) {
$record->studentlogs = 0;
}
if (!isset($record->chattime)) {
$record->chattime = time() - 2;
}
if (!isset($record->schedule)) {
$record->schedule = 0;
}
if (!isset($record->timemodified)) {
$record->timemodified = time();
}
return parent::create_instance($record, (array)$options);
}
}
+56
View File
@@ -0,0 +1,56 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_chat;
/**
* Generator tests class.
*
* @package mod_chat
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class generator_test extends \advanced_testcase {
/**
* Setup testcase.
*/
public function setUp(): void {
// Chat module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('chat', 1);
}
public function test_create_instance(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$this->assertFalse($DB->record_exists('chat', array('course' => $course->id)));
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id));
$this->assertEquals(1, $DB->count_records('chat', array('course' => $course->id)));
$this->assertTrue($DB->record_exists('chat', array('course' => $course->id)));
$this->assertTrue($DB->record_exists('chat', array('id' => $chat->id)));
$params = array('course' => $course->id, 'name' => 'One more chat');
$chat = $this->getDataGenerator()->create_module('chat', $params);
$this->assertEquals(2, $DB->count_records('chat', array('course' => $course->id)));
$this->assertEquals('One more chat', $DB->get_field_select('chat', 'name', 'id = :id', array('id' => $chat->id)));
}
}
+747
View File
@@ -0,0 +1,747 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Contains class containing unit tests for mod/chat/lib.php.
*
* @package mod_chat
* @category test
* @copyright 2017 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat;
defined('MOODLE_INTERNAL') || die();
/**
* Class containing unit tests for mod/chat/lib.php.
*
* @package mod_chat
* @category test
* @copyright 2017 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class lib_test extends \advanced_testcase {
public function setUp(): void {
$this->resetAfterTest();
// Chat module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('chat', 1);
}
/*
* The chat's event should not be shown to a user when the user cannot view the chat at all.
*/
public function test_chat_core_calendar_provide_event_action_in_hidden_section(): void {
global $CFG;
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Create a student.
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Create a chat.
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => usergetmidnight(time())));
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
// Set sections 0 as hidden.
set_section_visible($course->id, 0, 0);
// Now, log out.
$CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
$this->setUser();
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for the student.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory, $student->id);
// Confirm the event is not shown at all.
$this->assertNull($actionevent);
}
/*
* The chat's event should not be shown to a user who does not have permission to view the chat at all.
*/
public function test_chat_core_calendar_provide_event_action_for_non_user(): void {
global $CFG;
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Create a chat.
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => usergetmidnight(time())));
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
// Now, log out.
$CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
$this->setUser();
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory);
// Confirm the event is not shown at all.
$this->assertNull($actionevent);
}
public function test_chat_core_calendar_provide_event_action_chattime_event_yesterday(): void {
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Create a chat.
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => time() - DAYSECS));
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory);
// Confirm the event is not shown at all.
$this->assertNull($actionevent);
}
public function test_chat_core_calendar_provide_event_action_chattime_event_yesterday_for_user(): void {
global $CFG;
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Enrol a student in the course.
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Create a chat.
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => time() - DAYSECS));
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
// Now, log out.
$CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users have mod/chat:view capability by default.
$this->setUser();
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for the student.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory, $student->id);
// Confirm the event is not shown at all.
$this->assertNull($actionevent);
}
public function test_chat_core_calendar_provide_event_action_chattime_event_today(): void {
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Create a chat.
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => usergetmidnight(time())));
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory);
// Confirm the event was decorated.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
$this->assertEquals(get_string('enterchat', 'chat'), $actionevent->get_name());
$this->assertInstanceOf('moodle_url', $actionevent->get_url());
$this->assertEquals(1, $actionevent->get_item_count());
$this->assertTrue($actionevent->is_actionable());
}
public function test_chat_core_calendar_provide_event_action_chattime_event_today_for_user(): void {
global $CFG;
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Enrol a student in the course.
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Create a chat.
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => usergetmidnight(time())));
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
// Now, log out.
$CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users have mod/chat:view capability by default.
$this->setUser();
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for the student.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory, $student->id);
// Confirm the event was decorated.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
$this->assertEquals(get_string('enterchat', 'chat'), $actionevent->get_name());
$this->assertInstanceOf('moodle_url', $actionevent->get_url());
$this->assertEquals(1, $actionevent->get_item_count());
$this->assertTrue($actionevent->is_actionable());
}
public function test_chat_core_calendar_provide_event_action_chattime_event_tonight(): void {
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Create a chat.
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => usergetmidnight(time()) + (23 * HOURSECS)));
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory);
// Confirm the event was decorated.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
$this->assertEquals(get_string('enterchat', 'chat'), $actionevent->get_name());
$this->assertInstanceOf('moodle_url', $actionevent->get_url());
$this->assertEquals(1, $actionevent->get_item_count());
$this->assertTrue($actionevent->is_actionable());
}
public function test_chat_core_calendar_provide_event_action_chattime_event_tonight_for_user(): void {
global $CFG;
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Enrol a student in the course.
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Create a chat.
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => usergetmidnight(time()) + (23 * HOURSECS)));
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
// Now, log out.
$CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users have mod/chat:view capability by default.
$this->setUser();
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for the student.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory, $student->id);
// Confirm the event was decorated.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
$this->assertEquals(get_string('enterchat', 'chat'), $actionevent->get_name());
$this->assertInstanceOf('moodle_url', $actionevent->get_url());
$this->assertEquals(1, $actionevent->get_item_count());
$this->assertTrue($actionevent->is_actionable());
}
public function test_chat_core_calendar_provide_event_action_chattime_event_tomorrow(): void {
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Create a chat.
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => time() + DAYSECS));
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory);
// Confirm the event was decorated.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
$this->assertEquals(get_string('enterchat', 'chat'), $actionevent->get_name());
$this->assertInstanceOf('moodle_url', $actionevent->get_url());
$this->assertEquals(1, $actionevent->get_item_count());
$this->assertFalse($actionevent->is_actionable());
}
public function test_chat_core_calendar_provide_event_action_chattime_event_tomorrow_for_user(): void {
global $CFG;
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Enrol a student in the course.
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Create a chat.
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => time() + DAYSECS));
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
// Now, log out.
$CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users have mod/chat:view capability by default.
$this->setUser();
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for the student.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory, $student->id);
// Confirm the event was decorated.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
$this->assertEquals(get_string('enterchat', 'chat'), $actionevent->get_name());
$this->assertInstanceOf('moodle_url', $actionevent->get_url());
$this->assertEquals(1, $actionevent->get_item_count());
$this->assertFalse($actionevent->is_actionable());
}
public function test_chat_core_calendar_provide_event_action_chattime_event_different_timezones(): void {
global $CFG;
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
$hour = gmdate('H');
// This could have been much easier if MDL-37327 were implemented.
// We don't know when this test is being ran and there is no standard way to
// mock the time() function (MDL-37327 to handle that).
if ($hour < 10) {
$timezone1 = 'UTC'; // GMT.
$timezone2 = 'Pacific/Pago_Pago'; // GMT -11:00.
} else if ($hour < 11) {
$timezone1 = 'Pacific/Kiritimati'; // GMT +14:00.
$timezone2 = 'America/Sao_Paulo'; // GMT -03:00.
} else {
$timezone1 = 'Pacific/Kiritimati'; // GMT +14:00.
$timezone2 = 'UTC'; // GMT.
}
$this->setTimezone($timezone2);
// Enrol 2 students with different timezones in the course.
$student1 = $this->getDataGenerator()->create_and_enrol($course, 'student', (object)['timezone' => $timezone1]);
$student2 = $this->getDataGenerator()->create_and_enrol($course, 'student', (object)['timezone' => $timezone2]);
// Create a chat.
$chat1 = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => mktime(1, 0, 0))); // This is always yesterday in timezone1 time
// and always today in timezone2 time.
// Create a chat.
$chat2 = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
'chattime' => mktime(1, 0, 0) + DAYSECS)); // This is always today in timezone1 time
// and always tomorrow in timezone2 time.
// Create calendar events for the 2 chats above.
$event1 = $this->create_action_event($course->id, $chat1->id, CHAT_EVENT_TYPE_CHATTIME);
$event2 = $this->create_action_event($course->id, $chat2->id, CHAT_EVENT_TYPE_CHATTIME);
// Now, log out.
$CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users have mod/chat:view capability by default.
$this->setUser();
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for student1.
$actionevent11 = mod_chat_core_calendar_provide_event_action($event1, $factory, $student1->id);
$actionevent12 = mod_chat_core_calendar_provide_event_action($event1, $factory, $student2->id);
$actionevent21 = mod_chat_core_calendar_provide_event_action($event2, $factory, $student1->id);
$actionevent22 = mod_chat_core_calendar_provide_event_action($event2, $factory, $student2->id);
// Confirm event1 is not shown to student1 at all.
$this->assertNull($actionevent11, 'Failed for UTC time ' . gmdate('H:i'));
// Confirm event1 was decorated for student2 and it is actionable.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent12);
$this->assertEquals(get_string('enterchat', 'chat'), $actionevent12->get_name());
$this->assertInstanceOf('moodle_url', $actionevent12->get_url());
$this->assertEquals(1, $actionevent12->get_item_count());
$this->assertTrue($actionevent12->is_actionable());
// Confirm event2 was decorated for student1 and it is actionable.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent21);
$this->assertEquals(get_string('enterchat', 'chat'), $actionevent21->get_name());
$this->assertInstanceOf('moodle_url', $actionevent21->get_url());
$this->assertEquals(1, $actionevent21->get_item_count());
$this->assertTrue($actionevent21->is_actionable());
// Confirm event2 was decorated for student2 and it is not actionable.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent22);
$this->assertEquals(get_string('enterchat', 'chat'), $actionevent22->get_name());
$this->assertInstanceOf('moodle_url', $actionevent22->get_url());
$this->assertEquals(1, $actionevent22->get_item_count());
$this->assertFalse($actionevent22->is_actionable());
}
/**
* Test for chat_get_sessions().
*/
public function test_chat_get_sessions(): void {
global $DB;
$this->resetAfterTest();
$generator = $this->getDataGenerator();
// Setup test data.
$this->setAdminUser();
$course = $generator->create_course();
$chat = $generator->create_module('chat', ['course' => $course->id]);
$user1 = $generator->create_user();
$user2 = $generator->create_user();
$studentrole = $DB->get_record('role', ['shortname' => 'student']);
$generator->enrol_user($user1->id, $course->id, $studentrole->id);
$generator->enrol_user($user2->id, $course->id, $studentrole->id);
// Login as user 1.
$this->setUser($user1);
$chatsid = chat_login_user($chat->id, 'ajax', 0, $course);
$chatuser = $DB->get_record('chat_users', ['sid' => $chatsid]);
// Get the messages for this chat session.
$messages = chat_get_session_messages($chat->id, false, 0, 0, 'timestamp DESC');
// We should have just 1 system (enter) messages.
$this->assertCount(1, $messages);
// This is when the session starts (when the first message - enter - has been sent).
$sessionstart = reset($messages)->timestamp;
// Send some messages.
chat_send_chatmessage($chatuser, 'hello!');
chat_send_chatmessage($chatuser, 'bye bye!');
// Login as user 2.
$this->setUser($user2);
$chatsid = chat_login_user($chat->id, 'ajax', 0, $course);
$chatuser = $DB->get_record('chat_users', ['sid' => $chatsid]);
// Send a message and take note of this message ID.
$messageid = chat_send_chatmessage($chatuser, 'greetings!');
// This is when the session ends (timestamp of the last message sent to the chat).
$sessionend = $DB->get_field('chat_messages', 'timestamp', ['id' => $messageid]);
// Get the messages for this chat session.
$messages = chat_get_session_messages($chat->id, false, 0, 0, 'timestamp DESC');
// We should have 3 user and 2 system (enter) messages.
$this->assertCount(5, $messages);
// Fetch the chat sessions from the messages we retrieved.
$sessions = chat_get_sessions($messages, true);
// There should be only one session.
$this->assertCount(1, $sessions);
// Get this session.
$session = reset($sessions);
// Confirm that the start and end times of the session matches.
$this->assertEquals($sessionstart, $session->sessionstart);
$this->assertEquals($sessionend, $session->sessionend);
// Confirm we have 2 participants in the chat.
$this->assertCount(2, $session->sessionusers);
}
/**
* Test for chat_get_sessions with messages belonging to multiple sessions.
*/
public function test_chat_get_sessions_multiple(): void {
$messages = [];
$gap = 5; // 5 secs.
$now = time();
$timestamp = $now;
// Messages belonging to 3 sessions. Session 1 has 10 messages, 2 has 15, 3 has 25.
$sessionusers = [];
$sessiontimes = [];
$session = 0; // Incomplete session.
for ($i = 1; $i <= 50; $i++) {
// Take note of expected session times as we go through.
switch ($i) {
case 1:
// Session 1 start time.
$sessiontimes[0]['start'] = $timestamp;
break;
case 10:
// Session 1 end time.
$sessiontimes[0]['end'] = $timestamp;
break;
case 11:
// Session 2 start time.
$sessiontimes[1]['start'] = $timestamp;
break;
case 25:
// Session 2 end time.
$sessiontimes[1]['end'] = $timestamp;
break;
case 26:
// Session 3 start time.
$sessiontimes[2]['start'] = $timestamp;
break;
case 50:
// Session 3 end time.
$sessiontimes[2]['end'] = $timestamp;
break;
}
// User 1 to 5.
$user = rand(1, 5);
// Let's also include system messages as well. Give them to pop in 1-in-10 chance.
$issystem = rand(1, 10) == 10;
if ($issystem) {
$message = 'enter';
} else {
$message = 'Message ' . $i;
if (!isset($sessionusers[$session][$user])) {
$sessionusers[$session][$user] = 1;
} else {
$sessionusers[$session][$user]++;
}
}
$messages[] = (object)[
'id' => $i,
'chatid' => 1,
'userid' => $user,
'message' => $message,
'issystem' => $issystem,
'timestamp' => $timestamp,
];
// Set the next timestamp.
if ($i == 10 || $i == 25) {
// New session.
$session++;
$timestamp += CHAT_SESSION_GAP + 1;
} else {
$timestamp += $gap;
}
}
// Reverse sort the messages so they're in descending order.
rsort($messages);
// Get chat sessions showing only complete ones.
$completesessions = chat_get_sessions($messages);
// Session 1 is incomplete, so there should only be 2 sessions when $showall is false.
$this->assertCount(2, $completesessions);
// Reverse sort sessions so they are in ascending order matching our expected session times and users.
$completesessions = array_reverse($completesessions);
foreach ($completesessions as $index => $session) {
// We increment index by 1 because the incomplete expected session (index=0) is not included.
$expectedindex = $index + 1;
// Check the session users.
$users = $sessionusers[$expectedindex];
$this->assertCount(count($users), $session->sessionusers);
// Check the message counts for each user in this session.
foreach ($users as $userid => $messagecount) {
$this->assertEquals($messagecount, $session->sessionusers[$userid]);
}
$sessionstart = $sessiontimes[$expectedindex]['start'];
$sessionend = $sessiontimes[$expectedindex]['end'];
$this->assertEquals($sessionstart, $session->sessionstart);
$this->assertEquals($sessionend, $session->sessionend);
}
// Get all the chat sessions.
$allsessions = chat_get_sessions($messages, true);
// When showall is true, we should get 3 sessions.
$this->assertCount(3, $allsessions);
// Reverse sort sessions so they are in ascending order matching our expected session times and users.
$allsessions = array_reverse($allsessions);
foreach ($allsessions as $index => $session) {
// Check the session users.
$users = $sessionusers[$index];
$this->assertCount(count($users), $session->sessionusers);
// Check the message counts for each user in this session.
foreach ($users as $userid => $messagecount) {
$this->assertEquals($messagecount, $session->sessionusers[$userid]);
}
$sessionstart = $sessiontimes[$index]['start'];
$sessionend = $sessiontimes[$index]['end'];
$this->assertEquals($sessionstart, $session->sessionstart);
$this->assertEquals($sessionend, $session->sessionend);
}
}
public function test_chat_core_calendar_provide_event_action_already_completed(): void {
set_config('enablecompletion', 1);
$this->setAdminUser();
// Create the activity.
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id),
array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
// Get some additional data.
$cm = get_coursemodule_from_instance('chat', $chat->id);
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Mark the activity as completed.
$completion = new \completion_info($course);
$completion->set_module_viewed($cm);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory);
// Ensure result was null.
$this->assertNull($actionevent);
}
public function test_chat_core_calendar_provide_event_action_already_completed_for_user(): void {
set_config('enablecompletion', 1);
$this->setAdminUser();
// Create the activity.
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id),
array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
// Enrol a student in the course.
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Get some additional data.
$cm = get_coursemodule_from_instance('chat', $chat->id);
// Create a calendar event.
$event = $this->create_action_event($course->id, $chat->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Mark the activity as completed for the student.
$completion = new \completion_info($course);
$completion->set_module_viewed($cm, $student->id);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for the student.
$actionevent = mod_chat_core_calendar_provide_event_action($event, $factory, $student->id);
// Ensure result was null.
$this->assertNull($actionevent);
}
/**
* Creates an action event.
*
* @param int $courseid
* @param int $instanceid The chat id.
* @param string $eventtype The event type. eg. ASSIGN_EVENT_TYPE_DUE.
* @return bool|calendar_event
*/
private function create_action_event($courseid, $instanceid, $eventtype) {
$event = new \stdClass();
$event->name = 'Calendar event';
$event->modulename = 'chat';
$event->courseid = $courseid;
$event->instance = $instanceid;
$event->type = CALENDAR_EVENT_TYPE_ACTION;
$event->eventtype = $eventtype;
$event->timestart = time();
return \calendar_event::create($event);
}
/**
* A user who does not have capabilities to add events to the calendar should be able to create an chat.
*/
public function test_creation_with_no_calendar_capabilities(): void {
$this->resetAfterTest();
$course = self::getDataGenerator()->create_course();
$context = \context_course::instance($course->id);
$user = self::getDataGenerator()->create_and_enrol($course, 'editingteacher');
$roleid = self::getDataGenerator()->create_role();
self::getDataGenerator()->role_assign($roleid, $user->id, $context->id);
assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true);
$generator = self::getDataGenerator()->get_plugin_generator('mod_chat');
// Create an instance as a user without the calendar capabilities.
$this->setUser($user);
$params = array(
'course' => $course->id,
'chattime' => time() + 500,
);
$generator->create_instance($params);
}
}
+438
View File
@@ -0,0 +1,438 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Data provider tests.
*
* @package mod_chat
* @category test
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_chat\privacy;
defined('MOODLE_INTERNAL') || die();
global $CFG;
use core_privacy\tests\provider_testcase;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
use mod_chat\privacy\provider;
require_once($CFG->dirroot . '/mod/chat/lib.php');
/**
* Data provider testcase class.
*
* @package mod_chat
* @category test
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends provider_testcase {
public function setUp(): void {
global $PAGE;
$this->resetAfterTest();
$PAGE->get_renderer('core');
// Chat module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('chat', 1);
}
public function test_get_contexts_for_userid(): void {
global $DB;
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$chat1a = $dg->create_module('chat', ['course' => $c1]);
$chat1b = $dg->create_module('chat', ['course' => $c1]);
$chat2a = $dg->create_module('chat', ['course' => $c2]);
// Logins but no message.
$chatuser = $this->login_user_in_course_chat($u1, $c1, $chat1a);
// Logins and messages.
$chatuser = $this->login_user_in_course_chat($u1, $c1, $chat1b);
chat_send_chatmessage($chatuser, 'Hello world!');
// Silent login (no system message).
$chatuser = $this->login_user_in_course_chat($u1, $c2, $chat2a, 0, true);
// Silent login and messages.
$chatuser = $this->login_user_in_course_chat($u2, $c1, $chat1b, 0, true);
chat_send_chatmessage($chatuser, 'Ça va ?');
chat_send_chatmessage($chatuser, 'Moi, ça va.');
// Silent login and messages.
$chatuser = $this->login_user_in_course_chat($u2, $c2, $chat2a);
chat_send_chatmessage($chatuser, 'What\'s happening here?');
// Check contexts for user 1.
$contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
$this->assertCount(2, $contextids);
$this->assertTrue(in_array(\context_module::instance($chat1a->cmid)->id, $contextids));
$this->assertTrue(in_array(\context_module::instance($chat1b->cmid)->id, $contextids));
$contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
$this->assertCount(2, $contextids);
$this->assertTrue(in_array(\context_module::instance($chat1b->cmid)->id, $contextids));
$this->assertTrue(in_array(\context_module::instance($chat2a->cmid)->id, $contextids));
}
/**
* Test that only users with relevant contexts are fetched.
*/
public function test_get_users_in_context(): void {
$component = 'mod_chat';
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$chat1a = $dg->create_module('chat', ['course' => $c1]);
$chat1b = $dg->create_module('chat', ['course' => $c1]);
$chat2a = $dg->create_module('chat', ['course' => $c2]);
// Logins but no message.
$chatuser = $this->login_user_in_course_chat($u1, $c1, $chat1a);
// Logins and messages.
$chatuser = $this->login_user_in_course_chat($u1, $c1, $chat1b);
chat_send_chatmessage($chatuser, 'Hello world!');
// Silent login (no system message).
$chatuser = $this->login_user_in_course_chat($u1, $c2, $chat2a, 0, true);
// Silent login and messages.
$chatuser = $this->login_user_in_course_chat($u2, $c1, $chat1b, 0, true);
chat_send_chatmessage($chatuser, 'Ça va ?');
chat_send_chatmessage($chatuser, 'Moi, ça va.');
// Silent login and messages.
$chatuser = $this->login_user_in_course_chat($u2, $c2, $chat2a);
chat_send_chatmessage($chatuser, 'What\'s happening here?');
$context1a = \context_module::instance($chat1a->cmid);
$context1b = \context_module::instance($chat1b->cmid);
$context2a = \context_module::instance($chat2a->cmid);
$userlist1a = new \core_privacy\local\request\userlist($context1a, $component);
$userlist1b = new \core_privacy\local\request\userlist($context1b, $component);
$userlist2a = new \core_privacy\local\request\userlist($context2a, $component);
\mod_chat\privacy\provider::get_users_in_context($userlist1a);
\mod_chat\privacy\provider::get_users_in_context($userlist1b);
\mod_chat\privacy\provider::get_users_in_context($userlist2a);
// Ensure correct users are found in relevant contexts.
$this->assertCount(1, $userlist1a);
$expected = [$u1->id];
$actual = $userlist1a->get_userids();
$this->assertEquals($expected, $actual);
$this->assertCount(2, $userlist1b);
$expected = [$u1->id, $u2->id];
$actual = $userlist1b->get_userids();
sort($expected);
sort($actual);
$this->assertEquals($expected, $actual);
$this->assertCount(1, $userlist2a);
$expected = [$u1->id];
$actual = $userlist1a->get_userids();
$this->assertEquals($expected, $actual);
}
public function test_delete_data_for_all_users_in_context(): void {
global $DB;
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$chat1a = $dg->create_module('chat', ['course' => $c1]);
$chat1b = $dg->create_module('chat', ['course' => $c1]);
$chat1actx = \context_module::instance($chat1a->cmid);
$chat1bctx = \context_module::instance($chat1b->cmid);
$u1chat1a = $this->login_user_in_course_chat($u1, $c1, $chat1a);
$u2chat1a = $this->login_user_in_course_chat($u2, $c1, $chat1a);
chat_send_chatmessage($u1chat1a, 'Ça va ?');
chat_send_chatmessage($u2chat1a, 'Oui, et toi ?');
chat_send_chatmessage($u1chat1a, 'Bien merci.');
chat_send_chatmessage($u2chat1a, 'Pourquoi ils disent omelette "du" fromage ?!');
chat_send_chatmessage($u1chat1a, 'Aucune idée');
$this->assert_has_data_in_chat($u1, $chat1a);
$this->assert_has_data_in_chat($u2, $chat1a);
$u1chat1b = $this->login_user_in_course_chat($u1, $c1, $chat1b);
$u2chat1b = $this->login_user_in_course_chat($u2, $c1, $chat1b);
chat_send_chatmessage($u1chat1b, 'How are you going?');
chat_send_chatmessage($u2chat1b, 'Alright, you?');
chat_send_chatmessage($u1chat1b, 'Good, thanks.');
chat_send_chatmessage($u2chat1b, 'Sacre bleu!');
chat_send_chatmessage($u1chat1b, '\ö/');
$this->assert_has_data_in_chat($u1, $chat1b);
$this->assert_has_data_in_chat($u2, $chat1b);
// No change.
provider::delete_data_for_all_users_in_context(\context_course::instance($c1->id));
$this->assert_has_data_in_chat($u1, $chat1a);
$this->assert_has_data_in_chat($u2, $chat1a);
$this->assert_has_data_in_chat($u1, $chat1b);
$this->assert_has_data_in_chat($u2, $chat1b);
// Deletinge first chat does not affect other chat.
provider::delete_data_for_all_users_in_context($chat1actx);
$this->assert_has_no_data_in_chat($u1, $chat1a);
$this->assert_has_no_data_in_chat($u2, $chat1a);
$this->assert_has_data_in_chat($u1, $chat1b);
$this->assert_has_data_in_chat($u2, $chat1b);
}
public function test_delete_data_for_user(): void {
global $DB;
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$chat1a = $dg->create_module('chat', ['course' => $c1]);
$chat1b = $dg->create_module('chat', ['course' => $c1]);
$chat1actx = \context_module::instance($chat1a->cmid);
$chat1bctx = \context_module::instance($chat1b->cmid);
$u1chat1a = $this->login_user_in_course_chat($u1, $c1, $chat1a);
$u2chat1a = $this->login_user_in_course_chat($u2, $c1, $chat1a);
chat_send_chatmessage($u1chat1a, 'Ça va ?');
chat_send_chatmessage($u2chat1a, 'Oui, et toi ?');
chat_send_chatmessage($u1chat1a, 'Bien merci.');
chat_send_chatmessage($u2chat1a, 'Pourquoi ils disent omelette "du" fromage ?!');
chat_send_chatmessage($u1chat1a, 'Aucune idée');
$this->assert_has_data_in_chat($u1, $chat1a);
$this->assert_has_data_in_chat($u2, $chat1a);
$u1chat1b = $this->login_user_in_course_chat($u1, $c1, $chat1b);
$u2chat1b = $this->login_user_in_course_chat($u2, $c1, $chat1b);
chat_send_chatmessage($u1chat1b, 'How are you going?');
chat_send_chatmessage($u2chat1b, 'Alright, you?');
chat_send_chatmessage($u1chat1b, 'Good, thanks.');
chat_send_chatmessage($u2chat1b, 'Sacre bleu!');
chat_send_chatmessage($u1chat1b, '\ö/');
$this->assert_has_data_in_chat($u1, $chat1b);
$this->assert_has_data_in_chat($u2, $chat1b);
provider::delete_data_for_user(new approved_contextlist($u1, 'mod_chat', [$chat1actx->id]));
$this->assert_has_no_data_in_chat($u1, $chat1a);
$this->assert_has_data_in_chat($u2, $chat1a);
$this->assert_has_data_in_chat($u1, $chat1b);
$this->assert_has_data_in_chat($u2, $chat1b);
provider::delete_data_for_user(new approved_contextlist($u2, 'mod_chat', [$chat1actx->id, $chat1bctx->id]));
$this->assert_has_no_data_in_chat($u1, $chat1a);
$this->assert_has_no_data_in_chat($u2, $chat1a);
$this->assert_has_data_in_chat($u1, $chat1b);
$this->assert_has_no_data_in_chat($u2, $chat1b);
}
/**
* Test that data for users in approved userlist is deleted.
*/
public function test_delete_data_for_users(): void {
global $DB;
$component = 'mod_chat';
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$u3 = $dg->create_user();
$chat1 = $dg->create_module('chat', ['course' => $c1]);
$chat1context = \context_module::instance($chat1->cmid);
$u1chat1 = $this->login_user_in_course_chat($u1, $c1, $chat1);
$u2chat1 = $this->login_user_in_course_chat($u2, $c1, $chat1);
$u3chat1 = $this->login_user_in_course_chat($u3, $c1, $chat1);
chat_send_chatmessage($u1chat1, 'Ça va ?');
chat_send_chatmessage($u2chat1, 'Oui, et toi ?');
chat_send_chatmessage($u1chat1, 'Bien merci.');
chat_send_chatmessage($u2chat1, 'Pourquoi ils disent omelette "du" fromage ?!');
chat_send_chatmessage($u1chat1, 'Aucune idée');
chat_send_chatmessage($u3chat1, 'Je ne comprends pas');
$this->assert_has_data_in_chat($u1, $chat1);
$this->assert_has_data_in_chat($u2, $chat1);
$this->assert_has_data_in_chat($u3, $chat1);
$chat2 = $dg->create_module('chat', ['course' => $c1]);
$u1chat2 = $this->login_user_in_course_chat($u1, $c1, $chat2);
$u2chat2 = $this->login_user_in_course_chat($u2, $c1, $chat2);
$u3chat2 = $this->login_user_in_course_chat($u3, $c1, $chat2);
chat_send_chatmessage($u1chat2, 'Why do we have a separate chat?');
chat_send_chatmessage($u2chat2, 'I have no idea!');
chat_send_chatmessage($u3chat2, 'Me either.');
$this->assert_has_data_in_chat($u1, $chat2);
$this->assert_has_data_in_chat($u2, $chat2);
$this->assert_has_data_in_chat($u3, $chat2);
// Delete user 1 and 2 data from chat 1 context only.
$approveduserids = [$u1->id, $u2->id];
$approvedlist = new approved_userlist($chat1context, $component, $approveduserids);
provider::delete_data_for_users($approvedlist);
// Ensure correct chat data is deleted.
$this->assert_has_no_data_in_chat($u1, $chat1);
$this->assert_has_no_data_in_chat($u2, $chat1);
$this->assert_has_data_in_chat($u3, $chat1);
$this->assert_has_data_in_chat($u1, $chat2);
$this->assert_has_data_in_chat($u2, $chat2);
$this->assert_has_data_in_chat($u3, $chat2);
}
public function test_export_data_for_user(): void {
global $DB;
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$chat1a = $dg->create_module('chat', ['course' => $c1]);
$chat1b = $dg->create_module('chat', ['course' => $c1]);
$chat1actx = \context_module::instance($chat1a->cmid);
$chat1bctx = \context_module::instance($chat1b->cmid);
$u1chat1a = $this->login_user_in_course_chat($u1, $c1, $chat1a);
$u2chat1a = $this->login_user_in_course_chat($u2, $c1, $chat1a);
chat_send_chatmessage($u1chat1a, 'Ça va ?');
chat_send_chatmessage($u2chat1a, 'Oui, et toi ?');
chat_send_chatmessage($u1chat1a, 'Bien merci.');
chat_send_chatmessage($u2chat1a, 'Pourquoi ils disent omelette "du" fromage ?!');
chat_send_chatmessage($u1chat1a, 'Aucune idée');
chat_send_chatmessage($u1chat1a, 'exit', true);
$u1chat1b = $this->login_user_in_course_chat($u1, $c1, $chat1b);
$u2chat1b = $this->login_user_in_course_chat($u2, $c1, $chat1b);
chat_send_chatmessage($u1chat1b, 'How are you going?');
chat_send_chatmessage($u2chat1b, 'Alright, you?');
chat_send_chatmessage($u1chat1b, 'Good, thanks.');
chat_send_chatmessage($u2chat1b, 'Sacre bleu!');
chat_send_chatmessage($u1chat1b, '\ö/');
// Export for user 1 in chat 1.
provider::export_user_data(new approved_contextlist($u1, 'mod_chat', [$chat1actx->id]));
$data = writer::with_context($chat1actx)->get_data([]);
$this->assertNotEmpty($data);
$this->assertCount(5, $data->messages);
$this->assertEquals(get_string('messageenter', 'mod_chat', fullname($u1)), $data->messages[0]['message']);
$this->assertEquals(transform::yesno(true), $data->messages[0]['is_system_generated']);
$this->assertEquals('Ça va ?', $data->messages[1]['message']);
$this->assertEquals(transform::yesno(false), $data->messages[1]['is_system_generated']);
$this->assertEquals('Bien merci.', $data->messages[2]['message']);
$this->assertEquals(transform::yesno(false), $data->messages[2]['is_system_generated']);
$this->assertEquals('Aucune idée', $data->messages[3]['message']);
$this->assertEquals(transform::yesno(false), $data->messages[3]['is_system_generated']);
$this->assertEquals(get_string('messageexit', 'mod_chat', fullname($u1)), $data->messages[4]['message']);
$this->assertEquals(transform::yesno(true), $data->messages[4]['is_system_generated']);
$data = writer::with_context($chat1bctx)->get_data([]);
$this->assertEmpty($data);
// Export for user2 in chat 1 and 2.
writer::reset();
provider::export_user_data(new approved_contextlist($u2, 'mod_chat', [$chat1actx->id, $chat1bctx->id]));
$data = writer::with_context($chat1actx)->get_data([]);
$this->assertNotEmpty($data);
$this->assertCount(3, $data->messages);
$this->assertEquals(get_string('messageenter', 'mod_chat', fullname($u2)), $data->messages[0]['message']);
$this->assertEquals('Oui, et toi ?', $data->messages[1]['message']);
$this->assertEquals('Pourquoi ils disent omelette "du" fromage ?!', $data->messages[2]['message']);
$data = writer::with_context($chat1bctx)->get_data([]);
$this->assertNotEmpty($data);
$this->assertCount(3, $data->messages);
$this->assertEquals(get_string('messageenter', 'mod_chat', fullname($u2)), $data->messages[0]['message']);
$this->assertEquals('Alright, you?', $data->messages[1]['message']);
$this->assertEquals('Sacre bleu!', $data->messages[2]['message']);
}
/**
* Assert that there is data for a user in a chat.
*
* @param object $user The user.
* @param object $chat The chat.
* @return void
*/
protected function assert_has_data_in_chat($user, $chat) {
$this->assertTrue($this->has_data_in_chat($user, $chat));
}
/**
* Assert that there isn't any data for a user in a chat.
*
* @param object $user The user.
* @param object $chat The chat.
* @return void
*/
protected function assert_has_no_data_in_chat($user, $chat) {
$this->assertFalse($this->has_data_in_chat($user, $chat));
}
/**
* Check whether a user has data in a chat.
*
* @param object $user The user.
* @param object $chat The chat.
* @return bool
*/
protected function has_data_in_chat($user, $chat) {
global $DB;
return $DB->record_exists('chat_messages', ['chatid' => $chat->id, 'userid' => $user->id]);
}
/**
* Login a user in a chat.
*
* @param object $user The user.
* @param object $course The course.
* @param object $chat The chat.
* @param int $group The group number.
* @param bool $silent Whether we should advertise that the user logs in.
* @return object The chat user.
*/
protected function login_user_in_course_chat($user, $course, $chat, $group = 0, $silent = false) {
global $DB, $USER;
$origuser = $USER;
$this->setUser($user);
chat_login_user($chat->id, $silent ? 'sockets' : 'basic', 0, $course);
$chatuser = $DB->get_record('chat_users', ['userid' => $user->id, 'chatid' => $chat->id, 'groupid' => 0]);
$this->setUser($origuser);
return $chatuser;
}
}
+13
View File
@@ -0,0 +1,13 @@
This files describes API changes in /mod/chat/*,
information provided here is intended especially for developers.
=== 3.3.2 ===
* chat_refresh_events() Now takes two additional parameters to refine the update to a specific instance. This function
now optionally takes the module instance object or ID, and the course module object or ID. Please try to send the full
objects instead of the ids to save DB calls.
=== 2.4 ===
optional - no changes needed:
* previous references to icons c/user and c/group have been renamed to i/user and i/group.
+29
View File
@@ -0,0 +1,29 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Version information
*
* @package mod_chat
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024042200; // The current module version (Date: YYYYMMDDXX).
$plugin->requires = 2024041600; // Requires this Moodle version.
$plugin->component = 'mod_chat'; // Full name of the plugin (used for diagnostics).
+179
View File
@@ -0,0 +1,179 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
// This page prints a particular instance of chat.
require(__DIR__.'/../../config.php');
require_once($CFG->dirroot . '/mod/chat/lib.php');
require_once($CFG->libdir . '/completionlib.php');
$id = optional_param('id', 0, PARAM_INT);
$c = optional_param('c', 0, PARAM_INT);
$edit = optional_param('edit', -1, PARAM_BOOL);
if ($id) {
if (! $cm = get_coursemodule_from_id('chat', $id)) {
throw new \moodle_exception('invalidcoursemodule');
}
if (! $course = $DB->get_record('course', array('id' => $cm->course))) {
throw new \moodle_exception('coursemisconf');
}
chat_update_chat_times($cm->instance);
if (! $chat = $DB->get_record('chat', array('id' => $cm->instance))) {
throw new \moodle_exception('invalidid', 'chat');
}
} else {
chat_update_chat_times($c);
if (! $chat = $DB->get_record('chat', array('id' => $c))) {
throw new \moodle_exception('coursemisconf');
}
if (! $course = $DB->get_record('course', array('id' => $chat->course))) {
throw new \moodle_exception('coursemisconf');
}
if (! $cm = get_coursemodule_from_instance('chat', $chat->id, $course->id)) {
throw new \moodle_exception('invalidcoursemodule');
}
}
require_course_login($course, true, $cm);
$context = context_module::instance($cm->id);
$PAGE->set_context($context);
// Initialize $PAGE.
$courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
$title = $courseshortname . ': ' . format_string($chat->name);
$PAGE->set_url('/mod/chat/view.php', ['id' => $cm->id]);
$PAGE->set_title($title);
$PAGE->set_heading($course->fullname);
$PAGE->add_body_class('limitedwidth');
// Show some info for guests.
if (isguestuser()) {
echo $OUTPUT->header();
echo $OUTPUT->confirm('<p>'.get_string('noguests', 'chat').'</p>'.get_string('liketologin'),
get_login_url(), $CFG->wwwroot.'/course/view.php?id='.$course->id);
echo $OUTPUT->footer();
exit;
}
// Completion and trigger events.
chat_view($chat, $course, $cm, $context);
$strenterchat = get_string('enterchat', 'chat');
$stridle = get_string('idle', 'chat');
$strcurrentusers = get_string('currentusers', 'chat');
// Check to see if groups are being used here.
$groupmode = groups_get_activity_groupmode($cm);
$currentgroup = groups_get_activity_group($cm, true);
// URL parameters.
$params = array();
if ($currentgroup) {
$groupselect = " AND groupid = '$currentgroup'";
$groupparam = "_group{$currentgroup}";
$params['groupid'] = $currentgroup;
} else {
$groupselect = "";
$groupparam = "";
}
// Print the page header.
echo $OUTPUT->header();
if (has_capability('mod/chat:chat', $context)) {
$now = time();
$chattime = $chat->chattime ?? 0;
$span = $chattime - $now;
if (!empty($chat->schedule) && $span > 0) {
$attributes = ['class' => 'border bg-light rounded p-2'];
echo html_writer::tag('p', get_string('sessionstartsin', 'chat', format_time($span)), $attributes);
}
$params['id'] = $chat->id;
$chattarget = new moodle_url("/mod/chat/gui_$CFG->chat_method/index.php", $params);
echo html_writer::start_div('container-fluid tertiary-navigation');
echo html_writer::start_div('row');
echo html_writer::start_div('navitem');
echo $OUTPUT->action_link($chattarget,
$strenterchat,
new popup_action('click', $chattarget, "chat{$course->id}_{$chat->id}{$groupparam}",
array('height' => 500, 'width' => 700)), ['class' => 'btn btn-primary']);
echo html_writer::end_div();
echo html_writer::start_div('navitem');
$params['id'] = $chat->id;
$link = new moodle_url('/mod/chat/gui_basic/index.php', $params);
$action = new popup_action('click', $link, "chat{$course->id}_{$chat->id}{$groupparam}",
array('height' => 500, 'width' => 700));
echo $OUTPUT->action_link($link, get_string('noframesjs', 'message'), $action,
array('title' => get_string('modulename', 'chat'), 'class' => 'btn btn-secondary'));
echo html_writer::end_div();
echo html_writer::end_div();
echo html_writer::end_div();
// Print the main part of the page.
echo $OUTPUT->box_start('generalbox', 'enterlink');
if (($chat->studentlogs or has_capability('mod/chat:readlog', $context)) && !$PAGE->has_secondary_navigation()) {
if ($msg = chat_get_session_messages($chat->id, $currentgroup)) {
echo '<p>';
echo html_writer::link(new moodle_url('/mod/chat/report.php', array('id' => $cm->id)),
get_string('viewreport', 'chat'));
echo '</p>';
}
}
groups_print_activity_menu($cm, $CFG->wwwroot . "/mod/chat/view.php?id=$cm->id");
echo $OUTPUT->box_end();
} else {
groups_print_activity_menu($cm, $CFG->wwwroot . "/mod/chat/view.php?id=$cm->id");
echo $OUTPUT->box_start('generalbox', 'notallowenter');
echo '<p>'.get_string('notallowenter', 'chat').'</p>';
echo $OUTPUT->box_end();
}
chat_delete_old_users();
if ($chatusers = chat_get_users($chat->id, $currentgroup, $cm->groupingid)) {
$timenow = time();
echo $OUTPUT->box_start('generalbox', 'chatcurrentusers');
echo $OUTPUT->heading($strcurrentusers, 3);
echo '<table>';
foreach ($chatusers as $chatuser) {
$lastping = $timenow - $chatuser->lastmessageping;
echo '<tr><td class="chatuserimage">';
$url = new moodle_url('/user/view.php', array('id' => $chatuser->id, 'course' => $chat->course));
echo html_writer::link($url, $OUTPUT->user_picture($chatuser));
echo '</td><td class="chatuserdetails">';
echo '<p>'.fullname($chatuser).'</p>';
echo '<span class="idletime">'.$stridle.': '.format_time($lastping).'</span>';
echo '</td></tr>';
}
echo '</table>';
echo $OUTPUT->box_end();
}
echo $OUTPUT->footer();