MDL-55252 mod_chat: prevent direct script access to lib files.
[moodle.git] / mod / chat / lib.php
CommitLineData
848bb113 1<?php
848bb113 2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
1515a89e 16
848bb113 17/**
18 * Library of functions and constants for module chat
19 *
a6be3193 20 * @package mod_chat
848bb113 21 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
530d5535
SB
25defined('MOODLE_INTERNAL') || die();
26
89b8211e 27require_once($CFG->dirroot.'/calendar/lib.php');
c4d588cc 28
c52b4db5 29// The HTML head for the message window to start with (<!-- nix --> is used to get some browsers starting with output.
17da2e6f 30global $CHAT_HTMLHEAD;
1f8abb89 31$CHAT_HTMLHEAD = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\"><html><head></head>\n<body>\n\n".padding(200);
1515a89e 32
c52b4db5 33// The HTML head for the message window to start with (with js scrolling).
17da2e6f 34global $CHAT_HTMLHEAD_JS;
1f8abb89 35$CHAT_HTMLHEAD_JS = <<<EOD
36<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
37<html><head><script type="text/javascript">
38//<![CDATA[
c52b4db5 39function move() {
1f8abb89 40 if (scroll_active)
41 window.scroll(1,400000);
42 window.setTimeout("move()",100);
43}
44var scroll_active = true;
45move();
46//]]>
47</script>
48</head>
49<body onBlur="scroll_active = true" onFocus="scroll_active = false">
50EOD;
17da2e6f 51global $CHAT_HTMLHEAD_JS;
1f8abb89 52$CHAT_HTMLHEAD_JS .= padding(200);
1515a89e 53
c52b4db5 54// The HTML code for standard empty pages (e.g. if a user was kicked out).
17da2e6f 55global $CHAT_HTMLHEAD_OUT;
1f8abb89 56$CHAT_HTMLHEAD_OUT = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\"><html><head><title>You are out!</title></head><body></body></html>";
1515a89e 57
c52b4db5 58// The HTML head for the message input page.
17da2e6f 59global $CHAT_HTMLHEAD_MSGINPUT;
1f8abb89 60$CHAT_HTMLHEAD_MSGINPUT = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\"><html><head><title>Message Input</title></head><body>";
1515a89e 61
c52b4db5 62// The HTML code for the message input page, with JavaScript.
17da2e6f 63global $CHAT_HTMLHEAD_MSGINPUT_JS;
1d507186 64$CHAT_HTMLHEAD_MSGINPUT_JS = <<<EOD
65<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
66<html>
67 <head><title>Message Input</title>
68 <script type="text/javascript">
69 //<![CDATA[
70 scroll_active = true;
c52b4db5 71 function empty_field_and_submit() {
1d507186 72 document.fdummy.arsc_message.value=document.f.arsc_message.value;
73 document.fdummy.submit();
74 document.f.arsc_message.focus();
75 document.f.arsc_message.select();
76 return false;
77 }
78 //]]>
79 </script>
80 </head><body OnLoad="document.f.arsc_message.focus();document.f.arsc_message.select();">;
81EOD;
1515a89e 82
c52b4db5 83// Dummy data that gets output to the browser as needed, in order to make it show output.
17da2e6f 84global $CHAT_DUMMY_DATA;
6e5f40ea 85$CHAT_DUMMY_DATA = padding(200);
5c2f6a7f 86
848bb113 87/**
88 * @param int $n
89 * @return string
90 */
c52b4db5 91function padding($n) {
5c2f6a7f 92 $str = '';
c52b4db5
AD
93 for ($i = 0; $i < $n; $i++) {
94 $str .= "<!-- nix -->\n";
5c2f6a7f 95 }
96 return $str;
97}
1515a89e 98
848bb113 99/**
100 * Given an object containing all the necessary data,
101 * (defined by the form in mod_form.php) this function
102 * will create a new instance and return the id number
103 * of the new instance.
104 *
105 * @global object
106 * @param object $chat
107 * @return int
108 */
1515a89e 109function chat_add_instance($chat) {
c18269c7 110 global $DB;
1515a89e 111
112 $chat->timemodified = time();
113
a9637e7d
PS
114 $returnid = $DB->insert_record("chat", $chat);
115
b85b25eb 116 $event = new stdClass();
a9637e7d
PS
117 $event->name = $chat->name;
118 $event->description = format_module_intro('chat', $chat, $chat->coursemodule);
119 $event->courseid = $chat->course;
120 $event->groupid = 0;
121 $event->userid = 0;
122 $event->modulename = 'chat';
123 $event->instance = $returnid;
124 $event->eventtype = 'chattime';
125 $event->timestart = $chat->chattime;
126 $event->timeduration = 0;
127
128 calendar_event::create($event);
8496c4af 129
130 return $returnid;
1515a89e 131}
132
848bb113 133/**
134 * Given an object containing all the necessary data,
135 * (defined by the form in mod_form.php) this function
136 * will update an existing instance with new data.
137 *
138 * @global object
139 * @param object $chat
dd88de0e 140 * @return bool
848bb113 141 */
1515a89e 142function chat_update_instance($chat) {
c18269c7 143 global $DB;
1515a89e 144
145 $chat->timemodified = time();
146 $chat->id = $chat->instance;
147
dd88de0e 148 $DB->update_record("chat", $chat);
8496c4af 149
39790bd8 150 $event = new stdClass();
8496c4af 151
c52b4db5 152 if ($event->id = $DB->get_field('event', 'id', array('modulename' => 'chat', 'instance' => $chat->id))) {
8496c4af 153
dd88de0e
PS
154 $event->name = $chat->name;
155 $event->description = format_module_intro('chat', $chat, $chat->coursemodule);
156 $event->timestart = $chat->chattime;
8496c4af 157
dd88de0e
PS
158 $calendarevent = calendar_event::load($event->id);
159 $calendarevent->update($event);
8496c4af 160 }
161
dd88de0e 162 return true;
1515a89e 163}
164
848bb113 165/**
166 * Given an ID of an instance of this module,
167 * this function will permanently delete the instance
168 * and any data that depends on it.
169 *
170 * @global object
171 * @param int $id
172 * @return bool
173 */
1515a89e 174function chat_delete_instance($id) {
c18269c7 175 global $DB;
848bb113 176
c52b4db5 177 if (! $chat = $DB->get_record('chat', array('id' => $id))) {
1515a89e 178 return false;
179 }
180
181 $result = true;
182
c52b4db5 183 // Delete any dependent records here.
1515a89e 184
c52b4db5 185 if (! $DB->delete_records('chat', array('id' => $chat->id))) {
a71efae3 186 $result = false;
187 }
c52b4db5 188 if (! $DB->delete_records('chat_messages', array('chatid' => $chat->id))) {
a71efae3 189 $result = false;
190 }
c52b4db5 191 if (! $DB->delete_records('chat_messages_current', array('chatid' => $chat->id))) {
6e5f40ea 192 $result = false;
193 }
c52b4db5 194 if (! $DB->delete_records('chat_users', array('chatid' => $chat->id))) {
1515a89e 195 $result = false;
196 }
197
c52b4db5 198 if (! $DB->delete_records('event', array('modulename' => 'chat', 'instance' => $chat->id))) {
36eb856f 199 $result = false;
200 }
201
1515a89e 202 return $result;
203}
204
848bb113 205/**
206 * Given a course and a date, prints a summary of all chat rooms past and present
a3f66bde 207 * This function is called from block_recent_activity
848bb113 208 *
209 * @global object
210 * @global object
211 * @global object
212 * @param object $course
0b21e588 213 * @param bool $viewfullnames
848bb113 214 * @param int|string $timestart Timestamp
215 * @return bool
216 */
dd97c328 217function chat_print_recent_activity($course, $viewfullnames, $timestart) {
e09fc68b 218 global $CFG, $USER, $DB, $OUTPUT;
dd97c328 219
c52b4db5 220 // This is approximate only, but it is really fast.
dd97c328 221 $timeout = $CFG->chat_old_ping * 10;
222
d3bf6f92 223 if (!$mcms = $DB->get_records_sql("SELECT cm.id, MAX(chm.timestamp) AS lasttime
224 FROM {course_modules} cm
225 JOIN {modules} md ON md.id = cm.module
226 JOIN {chat} ch ON ch.id = cm.instance
227 JOIN {chat_messages} chm ON chm.chatid = ch.id
228 WHERE chm.timestamp > ? AND ch.course = ? AND md.name = 'chat'
229 GROUP BY cm.id
230 ORDER BY lasttime ASC", array($timestart, $course->id))) {
dd97c328 231 return false;
232 }
233
234 $past = array();
235 $current = array();
c52b4db5 236 $modinfo = get_fast_modinfo($course); // Reference needed because we might load the groups.
dd97c328 237
c52b4db5 238 foreach ($mcms as $cmid => $mcm) {
fd4d41c3 239 if (!array_key_exists($cmid, $modinfo->cms)) {
dd97c328 240 continue;
241 }
fd4d41c3 242 $cm = $modinfo->cms[$cmid];
dd97c328 243 if (!$modinfo->cms[$cm->id]->uservisible) {
244 continue;
245 }
b7602a11 246
dd97c328 247 if (groups_get_activity_groupmode($cm) != SEPARATEGROUPS
6536217c 248 or has_capability('moodle/site:accessallgroups', context_module::instance($cm->id))) {
55607eff 249 if ($timeout > time() - $mcm->lasttime) {
dd97c328 250 $current[] = $cm;
251 } else {
252 $past[] = $cm;
253 }
254
255 continue;
256 }
257
c52b4db5 258 // Verify groups in separate mode.
e19c086c 259 if (!$mygroupids = $modinfo->get_groups($cm->groupingid)) {
dd97c328 260 continue;
261 }
0469cccf 262
c52b4db5
AD
263 // Ok, last post was not for my group - we have to query db to get last message from one of my groups.
264 // The only minor problem is that the order will not be correct.
dd97c328 265 $mygroupids = implode(',', $mygroupids);
dd97c328 266
d3bf6f92 267 if (!$mcm = $DB->get_record_sql("SELECT cm.id, MAX(chm.timestamp) AS lasttime
268 FROM {course_modules} cm
269 JOIN {chat} ch ON ch.id = cm.instance
6e5f40ea 270 JOIN {chat_messages_current} chm ON chm.chatid = ch.id
d3bf6f92 271 WHERE chm.timestamp > ? AND cm.id = ? AND
272 (chm.groupid IN ($mygroupids) OR chm.groupid = 0)
273 GROUP BY cm.id", array($timestart, $cm->id))) {
dd97c328 274 continue;
275 }
fd4d41c3 276
55607eff
MG
277 $mcms[$cmid]->lasttime = $mcm->lasttime;
278 if ($timeout > time() - $mcm->lasttime) {
dd97c328 279 $current[] = $cm;
280 } else {
281 $past[] = $cm;
282 }
283 }
284
285 if (!$past and !$current) {
b7602a11 286 return false;
287 }
1515a89e 288
dd97c328 289 $strftimerecent = get_string('strftimerecent');
290
291 if ($past) {
97b97b63 292 echo $OUTPUT->heading(get_string("pastchats", 'chat').':', 3);
dd97c328 293
294 foreach ($past as $cm) {
295 $link = $CFG->wwwroot.'/mod/chat/view.php?id='.$cm->id;
55607eff 296 $date = userdate($mcms[$cm->id]->lasttime, $strftimerecent);
dd97c328 297 echo '<div class="head"><div class="date">'.$date.'</div></div>';
c52b4db5 298 echo '<div class="info"><a href="'.$link.'">'.format_string($cm->name, true).'</a></div>';
b7602a11 299 }
8f7dc7f1 300 }
301
302 if ($current) {
97b97b63 303 echo $OUTPUT->heading(get_string("currentchats", 'chat').':', 3);
dd97c328 304
c52b4db5 305 $oldest = floor((time() - $CFG->chat_old_ping) / 10) * 10; // Better db caching.
dd97c328 306
307 $timeold = time() - $CFG->chat_old_ping;
c52b4db5
AD
308 $timeold = floor($timeold / 10) * 10; // Better db caching.
309 $timeoldext = time() - ($CFG->chat_old_ping * 10); // JSless gui_basic needs much longer timeouts.
310 $timeoldext = floor($timeoldext / 10) * 10; // Better db caching.
dd97c328 311
c52b4db5 312 $params = array('timeold' => $timeold, 'timeoldext' => $timeoldext, 'cmid' => $cm->id);
d3bf6f92 313
488bbfb7 314 $timeout = "AND ((chu.version<>'basic' AND chu.lastping>:timeold) OR (chu.version='basic' AND chu.lastping>:timeoldext))";
dd97c328 315
316 foreach ($current as $cm) {
c52b4db5 317 // Count users first.
0eadedea
MG
318 $mygroupids = $modinfo->groups[$cm->groupingid];
319 if (!empty($mygroupids)) {
320 list($subquery, $subparams) = $DB->get_in_or_equal($mygroupids, SQL_PARAMS_NAMED, 'gid');
321 $params += $subparams;
322 $groupselect = "AND (chu.groupid $subquery OR chu.groupid = 0)";
dd97c328 323 } else {
324 $groupselect = "";
325 }
fd4d41c3 326
2072af6c
MN
327 $userfields = user_picture::fields('u');
328 if (!$users = $DB->get_records_sql("SELECT $userfields
d3bf6f92 329 FROM {course_modules} cm
330 JOIN {chat} ch ON ch.id = cm.instance
331 JOIN {chat_users} chu ON chu.chatid = ch.id
332 JOIN {user} u ON u.id = chu.userid
333 WHERE cm.id = :cmid $timeout $groupselect
1f47813b 334 GROUP BY $userfields", $params)) {
dd97c328 335 }
336
337 $link = $CFG->wwwroot.'/mod/chat/view.php?id='.$cm->id;
55607eff 338 $date = userdate($mcms[$cm->id]->lasttime, $strftimerecent);
dd97c328 339
340 echo '<div class="head"><div class="date">'.$date.'</div></div>';
c52b4db5 341 echo '<div class="info"><a href="'.$link.'">'.format_string($cm->name, true).'</a></div>';
dd97c328 342 echo '<div class="userlist">';
343 if ($users) {
344 echo '<ul>';
c52b4db5
AD
345 foreach ($users as $user) {
346 echo '<li>'.fullname($user, $viewfullnames).'</li>';
347 }
dd97c328 348 echo '</ul>';
349 }
350 echo '</div>';
351 }
b7602a11 352 }
353
354 return true;
1515a89e 355}
356
848bb113 357/**
358 * Function to be run periodically according to the moodle cron
359 * This function searches for things that need to be done, such
360 * as sending out mail, toggling flags etc ...
361 *
362 * @global object
363 * @return bool
364 */
1515a89e 365function chat_cron () {
d3bf6f92 366 global $DB;
1515a89e 367
fcd3a1ee 368 chat_update_chat_times();
369
7d792369 370 chat_delete_old_users();
371
c52b4db5 372 // Delete old messages with a single SQL query.
319038c3 373 $subselect = "SELECT c.keepdays
d3bf6f92 374 FROM {chat} c
375 WHERE c.id = {chat_messages}.chatid";
4388027c 376
319038c3 377 $sql = "DELETE
d3bf6f92 378 FROM {chat_messages}
6e5f40ea 379 WHERE ($subselect) > 0 AND timestamp < ( ".time()." -($subselect) * 24 * 3600)";
380
381 $DB->execute($sql);
382
383 $sql = "DELETE
384 FROM {chat_messages_current}
385 WHERE timestamp < ( ".time()." - 8 * 3600)";
4388027c 386
d3bf6f92 387 $DB->execute($sql);
22a4491a 388
1515a89e 389 return true;
390}
391
848bb113 392/**
393 * This standard function will check all instances of this module
394 * and make sure there are up-to-date events created for each of them.
395 * If courseid = 0, then every chat event in the site is checked, else
396 * only chat events belonging to the course specified are checked.
397 * This function is used, in its new format, by restore_refresh_events()
398 *
399 * @global object
400 * @param int $courseid
401 * @return bool
402 */
8496c4af 403function chat_refresh_events($courseid = 0) {
d3bf6f92 404 global $DB;
8496c4af 405
406 if ($courseid) {
c52b4db5 407 if (! $chats = $DB->get_records("chat", array("course" => $courseid))) {
8496c4af 408 return true;
409 }
410 } else {
d3bf6f92 411 if (! $chats = $DB->get_records("chat")) {
8496c4af 412 return true;
413 }
414 }
c52b4db5 415 $moduleid = $DB->get_field('modules', 'id', array('name' => 'chat'));
8496c4af 416
417 foreach ($chats as $chat) {
a646cd56 418 $cm = get_coursemodule_from_instance('chat', $chat->id, $chat->course);
39790bd8 419 $event = new stdClass();
d3bf6f92 420 $event->name = $chat->name;
9b010a10 421 $event->description = format_module_intro('chat', $chat, $cm->id);
8496c4af 422 $event->timestart = $chat->chattime;
423
c52b4db5 424 if ($event->id = $DB->get_field('event', 'id', array('modulename' => 'chat', 'instance' => $chat->id))) {
89b8211e
SH
425 $calendarevent = calendar_event::load($event->id);
426 $calendarevent->update($event);
8496c4af 427 } else {
428 $event->courseid = $chat->course;
429 $event->groupid = 0;
430 $event->userid = 0;
431 $event->modulename = 'chat';
432 $event->instance = $chat->id;
a48bf079 433 $event->eventtype = 'chattime';
8496c4af 434 $event->timeduration = 0;
c52b4db5 435 $event->visible = $DB->get_field('course_modules', 'visible', array('module' => $moduleid, 'instance' => $chat->id));
b5de723d 436
89b8211e 437 calendar_event::create($event);
8496c4af 438 }
439 }
440 return true;
441}
442
c52b4db5 443// Functions that require some SQL.
1515a89e 444
848bb113 445/**
446 * @global object
447 * @param int $chatid
448 * @param int $groupid
449 * @param int $groupingid
450 * @return array
451 */
a12e11c1 452function chat_get_users($chatid, $groupid=0, $groupingid=0) {
d3bf6f92 453 global $DB;
1515a89e 454
c52b4db5 455 $params = array('chatid' => $chatid, 'groupid' => $groupid, 'groupingid' => $groupingid);
84a2fdd7 456
457 if ($groupid) {
d3bf6f92 458 $groupselect = " AND (c.groupid=:groupid OR c.groupid='0')";
84a2fdd7 459 } else {
460 $groupselect = "";
461 }
6e5f40ea 462
98da6021 463 if (!empty($groupingid)) {
d3bf6f92 464 $groupingjoin = "JOIN {groups_members} gm ON u.id = gm.userid
465 JOIN {groupings_groups} gg ON gm.groupid = gg.groupid AND gg.groupingid = :groupingid ";
6e5f40ea 466
a12e11c1 467 } else {
468 $groupingjoin = '';
469 }
b5de723d 470
3a11c09f
PS
471 $ufields = user_picture::fields('u');
472 return $DB->get_records_sql("SELECT DISTINCT $ufields, c.lastmessageping, c.firstping
473 FROM {chat_users} c
474 JOIN {user} u ON u.id = c.userid $groupingjoin
475 WHERE c.chatid = :chatid $groupselect
476 ORDER BY c.firstping ASC", $params);
1515a89e 477}
478
848bb113 479/**
480 * @global object
481 * @param int $chatid
482 * @param int $groupid
483 * @return array
484 */
84a2fdd7 485function chat_get_latest_message($chatid, $groupid=0) {
f33e1ed4 486 global $DB;
1515a89e 487
c52b4db5 488 $params = array('chatid' => $chatid, 'groupid' => $groupid);
1515a89e 489
84a2fdd7 490 if ($groupid) {
d3bf6f92 491 $groupselect = "AND (groupid=:groupid OR groupid=0)";
84a2fdd7 492 } else {
493 $groupselect = "";
494 }
495
e7521559 496 $sql = "SELECT *
547ac664 497 FROM {chat_messages_current} WHERE chatid = :chatid $groupselect
498 ORDER BY timestamp DESC";
03cedd62 499
c52b4db5 500 // Return the lastest one message.
f33e1ed4 501 return $DB->get_record_sql($sql, $params, true);
1515a89e 502}
503
848bb113 504/**
505 * login if not already logged in
506 *
507 * @global object
508 * @global object
509 * @param int $chatid
510 * @param string $version
511 * @param int $groupid
512 * @param object $course
513 * @return bool|int Returns the chat users sid or false
514 */
a32c7772 515function chat_login_user($chatid, $version, $groupid, $course) {
d3bf6f92 516 global $USER, $DB;
517
c52b4db5
AD
518 if (($version != 'sockets') and $chatuser = $DB->get_record('chat_users', array('chatid' => $chatid,
519 'userid' => $USER->id,
520 'groupid' => $groupid))) {
521 // This will update logged user information.
516121bd 522 $chatuser->version = $version;
d96466d2 523 $chatuser->ip = $USER->lastip;
516121bd 524 $chatuser->lastping = time();
525 $chatuser->lang = current_language();
1515a89e 526
c52b4db5
AD
527 // Sometimes $USER->lastip is not setup properly during login.
528 // Update with current value if possible or provide a dummy value for the db.
d13ef2fb 529 if (empty($chatuser->ip)) {
530 $chatuser->ip = getremoteaddr();
d13ef2fb 531 }
532
7f0483f6 533 if (($chatuser->course != $course->id) or ($chatuser->userid != $USER->id)) {
516121bd 534 return false;
535 }
a8c31db2 536 $DB->update_record('chat_users', $chatuser);
537
516121bd 538 } else {
39790bd8 539 $chatuser = new stdClass();
516121bd 540 $chatuser->chatid = $chatid;
541 $chatuser->userid = $USER->id;
542 $chatuser->groupid = $groupid;
543 $chatuser->version = $version;
d96466d2 544 $chatuser->ip = $USER->lastip;
516121bd 545 $chatuser->lastping = $chatuser->firstping = $chatuser->lastmessageping = time();
546 $chatuser->sid = random_string(32);
c52b4db5
AD
547 $chatuser->course = $course->id; // Caching - needed for current_language too.
548 $chatuser->lang = current_language(); // Caching - to resource intensive to find out later.
516121bd 549
c52b4db5
AD
550 // Sometimes $USER->lastip is not setup properly during login.
551 // Update with current value if possible or provide a dummy value for the db.
274f0091 552 if (empty($chatuser->ip)) {
553 $chatuser->ip = getremoteaddr();
274f0091 554 }
555
a8c31db2 556 $DB->insert_record('chat_users', $chatuser);
516121bd 557
a32c7772 558 if ($version == 'sockets') {
c52b4db5 559 // Do not send 'enter' message, chatd will do it.
a32c7772 560 } else {
f49d814a 561 chat_send_chatmessage($chatuser, 'enter', true);
516121bd 562 }
1515a89e 563 }
564
565 return $chatuser->sid;
566}
567
848bb113 568/**
569 * Delete the old and in the way
570 *
571 * @global object
572 * @global object
573 */
7d792369 574function chat_delete_old_users() {
c52b4db5 575 // Delete the old and in the way.
d3bf6f92 576 global $CFG, $DB;
b5012f3e 577
e7fbd0b3 578 $timeold = time() - $CFG->chat_old_ping;
c52b4db5 579 $timeoldext = time() - ($CFG->chat_old_ping * 10); // JSless gui_basic needs much longer timeouts.
a32c7772 580
d3bf6f92 581 $query = "(version<>'basic' AND lastping<?) OR (version='basic' AND lastping<?)";
582 $params = array($timeold, $timeoldext);
7d792369 583
d3bf6f92 584 if ($oldusers = $DB->get_records_select('chat_users', $query, $params) ) {
585 $DB->delete_records_select('chat_users', $query, $params);
7d792369 586 foreach ($oldusers as $olduser) {
f49d814a 587 chat_send_chatmessage($olduser, 'exit', true);
7d792369 588 }
589 }
590}
1515a89e 591
848bb113 592/**
593 * Updates chat records so that the next chat time is correct
594 *
595 * @global object
596 * @param int $chatid
597 * @return void
598 */
fcd3a1ee 599function chat_update_chat_times($chatid=0) {
c52b4db5 600 // Updates chat records so that the next chat time is correct.
d3bf6f92 601 global $DB;
fcd3a1ee 602
603 $timenow = time();
d3bf6f92 604
c52b4db5 605 $params = array('timenow' => $timenow, 'chatid' => $chatid);
d3bf6f92 606
fcd3a1ee 607 if ($chatid) {
d3bf6f92 608 if (!$chats[] = $DB->get_record_select("chat", "id = :chatid AND chattime <= :timenow AND schedule > 0", $params)) {
fcd3a1ee 609 return;
610 }
611 } else {
d3bf6f92 612 if (!$chats = $DB->get_records_select("chat", "chattime <= :timenow AND schedule > 0", $params)) {
fcd3a1ee 613 return;
614 }
615 }
616
617 foreach ($chats as $chat) {
618 switch ($chat->schedule) {
c52b4db5
AD
619 case 1: // Single event - turn off schedule and disable.
620 $chat->chattime = 0;
621 $chat->schedule = 0;
622 break;
623 case 2: // Repeat daily.
624 while ($chat->chattime <= $timenow) {
625 $chat->chattime += 24 * 3600;
626 }
627 break;
628 case 3: // Repeat weekly.
629 while ($chat->chattime <= $timenow) {
630 $chat->chattime += 7 * 24 * 3600;
631 }
632 break;
fcd3a1ee 633 }
d3bf6f92 634 $DB->update_record("chat", $chat);
635
c52b4db5 636 $event = new stdClass(); // Update calendar too.
8496c4af 637
d3bf6f92 638 $cond = "modulename='chat' AND instance = :chatid AND timestart <> :chattime";
600b8152 639 $params = array('chattime' => $chat->chattime, 'chatid' => $chat->id);
d3bf6f92 640
641 if ($event->id = $DB->get_field_select('event', 'id', $cond, $params)) {
8496c4af 642 $event->timestart = $chat->chattime;
89b8211e 643 $calendarevent = calendar_event::load($event->id);
1d5bd3d2 644 $calendarevent->update($event, false);
8496c4af 645 }
fcd3a1ee 646 }
647}
648
f49d814a
FM
649/**
650 * Send a message on the chat.
651 *
652 * @param object $chatuser The chat user record.
653 * @param string $messagetext The message to be sent.
654 * @param bool $system False for non-system messages, true for system messages.
655 * @param object $cm The course module object, pass it to save a database query when we trigger the event.
656 * @return int The message ID.
5bcfd504 657 * @since Moodle 2.6
f49d814a
FM
658 */
659function chat_send_chatmessage($chatuser, $messagetext, $system = false, $cm = null) {
660 global $DB;
661
662 $message = new stdClass();
663 $message->chatid = $chatuser->chatid;
664 $message->userid = $chatuser->userid;
665 $message->groupid = $chatuser->groupid;
666 $message->message = $messagetext;
667 $message->system = $system ? 1 : 0;
668 $message->timestamp = time();
669
670 $messageid = $DB->insert_record('chat_messages', $message);
671 $DB->insert_record('chat_messages_current', $message);
672 $message->id = $messageid;
673
674 if (!$system) {
675
676 if (empty($cm)) {
677 $cm = get_coursemodule_from_instance('chat', $chatuser->chatid, $chatuser->course);
678 }
679
680 $params = array(
681 'context' => context_module::instance($cm->id),
682 'objectid' => $message->id,
683 // We set relateduserid, because when triggered from the chat daemon, the event userid is null.
684 'relateduserid' => $chatuser->userid
685 );
686 $event = \mod_chat\event\message_sent::create($params);
687 $event->add_record_snapshot('chat_messages', $message);
688 $event->trigger();
689 }
690
691 return $message->id;
692}
693
848bb113 694/**
695 * @global object
696 * @global object
697 * @param object $message
698 * @param int $courseid
699 * @param object $sender
700 * @param object $currentuser
c52b4db5 701 * @param string $chatlastrow
848bb113 702 * @return bool|string Returns HTML or false
703 */
c52b4db5 704function chat_format_message_manually($message, $courseid, $sender, $currentuser, $chatlastrow = null) {
d3222955 705 global $CFG, $USER, $OUTPUT;
1515a89e 706
39790bd8 707 $output = new stdClass();
c52b4db5
AD
708 $output->beep = false; // By default.
709 $output->refreshusers = false; // By default.
7d792369 710
d6e7a63d
PS
711 // Find the correct timezone for displaying this message.
712 $tz = core_date::get_user_timezone($currentuser);
713
b5de723d 714 $message->strtime = userdate($message->timestamp, get_string('strftimemessage', 'chat'), $tz);
715
c52b4db5 716 $message->picture = $OUTPUT->user_picture($sender, array('size' => false, 'courseid' => $courseid, 'link' => false));
d3222955 717
75d07096 718 if ($courseid) {
c52b4db5 719 $message->picture = "<a onclick=\"window.open('$CFG->wwwroot/user/view.php?id=$sender->id&amp;course=$courseid')\"".
5eb1703c 720 " href=\"$CFG->wwwroot/user/view.php?id=$sender->id&amp;course=$courseid\">$message->picture</a>";
582de679 721 }
1515a89e 722
c52b4db5
AD
723 // Calculate the row class.
724 if ($chatlastrow !== null) {
725 $rowclass = ' class="r'.$chatlastrow.'" ';
aa5c32fd 726 } else {
727 $rowclass = '';
728 }
729
c52b4db5 730 // Start processing the message.
75d07096 731
c52b4db5
AD
732 if (!empty($message->system)) {
733 // System event.
75d07096 734 $output->text = $message->strtime.': '.get_string('message'.$message->message, 'chat', fullname($sender));
c52b4db5
AD
735 $output->html = '<table class="chat-event"><tr'.$rowclass.'><td class="picture">'.$message->picture.'</td>';
736 $output->html .= '<td class="text"><span class="event">'.$output->text.'</span></td></tr></table>';
83f47164
JM
737 $output->basic = '<tr class="r1">
738 <th scope="row" class="cell c1 title"></th>
739 <td class="cell c2 text">' . get_string('message'.$message->message, 'chat', fullname($sender)) . '</td>
740 <td class="cell c3">' . $message->strtime . '</td>
741 </tr>';
c52b4db5
AD
742 if ($message->message == 'exit' or $message->message == 'enter') {
743 $output->refreshusers = true; // Force user panel refresh ASAP.
516121bd 744 }
75d07096 745 return $output;
1515a89e 746 }
747
c52b4db5 748 // It's not a system event.
6c6ed54a 749 $text = trim($message->message);
82a524ef 750
c52b4db5 751 // Parse the text to clean and filter it.
39790bd8 752 $options = new stdClass();
82a524ef 753 $options->para = false;
cd29373c 754 $options->blanktarget = true;
82a524ef 755 $text = format_text($text, FORMAT_MOODLE, $options, $courseid);
927a7808 756
c52b4db5
AD
757 // And now check for special cases.
758 $patternto = '#^\s*To\s([^:]+):(.*)#';
927a7808 759 $special = false;
760
b5de723d 761 if (substr($text, 0, 5) == 'beep ') {
c52b4db5 762 // It's a beep!
927a7808 763 $special = true;
7d792369 764 $beepwho = trim(substr($text, 5));
9f85bed4 765
c52b4db5 766 if ($beepwho == 'all') { // Everyone.
83f47164
JM
767 $outinfobasic = get_string('messagebeepseveryone', 'chat', fullname($sender));
768 $outinfo = $message->strtime . ': ' . $outinfobasic;
75d07096 769 $outmain = '';
83f47164 770
c52b4db5 771 $output->beep = true; // Eventually this should be set to a filename uploaded by the user.
7d792369 772
c52b4db5 773 } else if ($beepwho == $currentuser->id) { // Current user.
83f47164
JM
774 $outinfobasic = get_string('messagebeepsyou', 'chat', fullname($sender));
775 $outinfo = $message->strtime . ': ' . $outinfobasic;
75d07096 776 $outmain = '';
777 $output->beep = true;
264867fd 778
c52b4db5 779 } else { // Something is not caught?
7d792369 780 return false;
781 }
c52b4db5 782 } else if (substr($text, 0, 1) == '/') { // It's a user command.
6c6ed54a 783 $special = true;
1d507186 784 $pattern = '#(^\/)(\w+).*#';
6c6ed54a
FM
785 preg_match($pattern, $text, $matches);
786 $command = isset($matches[2]) ? $matches[2] : false;
787 // Support some IRC commands.
c52b4db5 788 switch ($command) {
6c6ed54a
FM
789 case 'me':
790 $outinfo = $message->strtime;
791 $outmain = '*** <b>'.$sender->firstname.' '.substr($text, 4).'</b>';
792 break;
793 default:
794 // Error, we set special back to false to use the classic message output.
795 $special = false;
796 break;
1515a89e 797 }
c52b4db5 798 } else if (preg_match($patternto, $text)) {
7f0483f6 799 $special = true;
6c6ed54a 800 $matches = array();
c52b4db5 801 preg_match($patternto, $text, $matches);
6c6ed54a
FM
802 if (isset($matches[1]) && isset($matches[2])) {
803 $outinfo = $message->strtime;
804 $outmain = $sender->firstname.' '.get_string('saidto', 'chat').' <i>'.$matches[1].'</i>: '.$matches[2];
805 } else {
806 // Error, we set special back to false to use the classic message output.
807 $special = false;
808 }
927a7808 809 }
9f85bed4 810
c52b4db5 811 if (!$special) {
75d07096 812 $outinfo = $message->strtime.' '.$sender->firstname;
7d792369 813 $outmain = $text;
1515a89e 814 }
264867fd 815
c52b4db5 816 // Format the message as a small table.
1515a89e 817
75d07096 818 $output->text = strip_tags($outinfo.': '.$outmain);
7d792369 819
c52b4db5
AD
820 $output->html = "<table class=\"chat-message\"><tr$rowclass><td class=\"picture\" valign=\"top\">$message->picture</td>";
821 $output->html .= "<td class=\"text\"><span class=\"title\">$outinfo</span>";
75d07096 822 if ($outmain) {
823 $output->html .= ": $outmain";
83f47164
JM
824 $output->basic = '<tr class="r0">
825 <th scope="row" class="cell c1 title">' . $sender->firstname . '</th>
826 <td class="cell c2 text">' . $outmain . '</td>
827 <td class="cell c3">' . $message->strtime . '</td>
828 </tr>';
6ee78cee 829 } else {
83f47164
JM
830 $output->basic = '<tr class="r1">
831 <th scope="row" class="cell c1 title"></th>
832 <td class="cell c2 text">' . $outinfobasic . '</td>
833 <td class="cell c3">' . $message->strtime . '</td>
834 </tr>';
7d792369 835 }
75d07096 836 $output->html .= "</td></tr></table>";
837 return $output;
b5de723d 838}
839
848bb113 840/**
c52b4db5 841 * Given a message object this function formats it appropriately into text and html then returns the formatted data
848bb113 842 * @global object
843 * @param object $message
844 * @param int $courseid
845 * @param object $currentuser
c52b4db5 846 * @param string $chatlastrow
848bb113 847 * @return bool|string Returns HTML or false
848 */
c52b4db5 849function chat_format_message($message, $courseid, $currentuser, $chatlastrow=null) {
d3bf6f92 850 global $DB;
b5de723d 851
c52b4db5 852 static $users; // Cache user lookups.
78c98892 853
854 if (isset($users[$message->userid])) {
855 $user = $users[$message->userid];
c52b4db5 856 } else if ($user = $DB->get_record('user', array('id' => $message->userid), user_picture::fields())) {
78c98892 857 $users[$message->userid] = $user;
858 } else {
c52b4db5 859 return null;
b5de723d 860 }
c52b4db5 861 return chat_format_message_manually($message, $courseid, $user, $currentuser, $chatlastrow);
1515a89e 862}
863
75d07096 864/**
865 * @global object
d0157d82
RT
866 * @param object $message message to be displayed.
867 * @param mixed $chatuser user chat data
868 * @param object $currentuser current user for whom the message should be displayed.
869 * @param int $groupingid course module grouping id
870 * @param string $theme name of the chat theme.
75d07096 871 * @return bool|string Returns HTML or false
872 */
d0157d82 873function chat_format_message_theme ($message, $chatuser, $currentuser, $groupingid, $theme = 'bubble') {
a2592fec
AD
874 global $CFG, $USER, $OUTPUT, $COURSE, $DB, $PAGE;
875 require_once($CFG->dirroot.'/mod/chat/locallib.php');
75d07096 876
c52b4db5 877 static $users; // Cache user lookups.
75d07096 878
39790bd8 879 $result = new stdClass();
75d07096 880
881 if (file_exists($CFG->dirroot . '/mod/chat/gui_ajax/theme/'.$theme.'/config.php')) {
882 include($CFG->dirroot . '/mod/chat/gui_ajax/theme/'.$theme.'/config.php');
883 }
884
885 if (isset($users[$message->userid])) {
886 $sender = $users[$message->userid];
c52b4db5 887 } else if ($sender = $DB->get_record('user', array('id' => $message->userid), user_picture::fields())) {
75d07096 888 $users[$message->userid] = $sender;
889 } else {
c52b4db5 890 return null;
75d07096 891 }
892
d6e7a63d
PS
893 // Find the correct timezone for displaying this message.
894 $tz = core_date::get_user_timezone($currentuser);
75d07096 895
d0157d82 896 if (empty($chatuser->course)) {
75d07096 897 $courseid = $COURSE->id;
d0157d82
RT
898 } else {
899 $courseid = $chatuser->course;
75d07096 900 }
901
902 $message->strtime = userdate($message->timestamp, get_string('strftimemessage', 'chat'), $tz);
c52b4db5 903 $message->picture = $OUTPUT->user_picture($sender, array('courseid' => $courseid));
75d07096 904
c52b4db5 905 $message->picture = "<a target='_blank'".
56302d48 906 " href=\"$CFG->wwwroot/user/view.php?id=$sender->id&amp;course=$courseid\">$message->picture</a>";
75d07096 907
c52b4db5
AD
908 // Start processing the message.
909 if (!empty($message->system)) {
75d07096 910 $result->type = 'system';
911
a2592fec
AD
912 $senderprofile = $CFG->wwwroot.'/user/view.php?id='.$sender->id.'&amp;course='.$courseid;
913 $event = get_string('message'.$message->message, 'chat', fullname($sender));
914 $eventmessage = new event_message($senderprofile, fullname($sender), $message->strtime, $event, $theme);
915
916 $output = $PAGE->get_renderer('mod_chat');
917 $result->html = $output->render($eventmessage);
918
75d07096 919 return $result;
920 }
921
c52b4db5 922 // It's not a system event.
6c6ed54a 923 $text = trim($message->message);
75d07096 924
c52b4db5 925 // Parse the text to clean and filter it.
39790bd8 926 $options = new stdClass();
75d07096 927 $options->para = false;
cd29373c 928 $options->blanktarget = true;
75d07096 929 $text = format_text($text, FORMAT_MOODLE, $options, $courseid);
930
c52b4db5 931 // And now check for special cases.
75d07096 932 $special = false;
933 $outtime = $message->strtime;
934
6c6ed54a 935 // Initialise variables.
d0157d82 936 $outmain = '';
c52b4db5 937 $patternto = '#^\s*To\s([^:]+):(.*)#';
d0157d82 938
75d07096 939 if (substr($text, 0, 5) == 'beep ') {
940 $special = true;
c52b4db5 941 // It's a beep!
75d07096 942 $result->type = 'beep';
943 $beepwho = trim(substr($text, 5));
944
c52b4db5
AD
945 if ($beepwho == 'all') { // Everyone.
946 $outmain = get_string('messagebeepseveryone', 'chat', fullname($sender));
947 } else if ($beepwho == $currentuser->id) { // Current user.
75d07096 948 $outmain = get_string('messagebeepsyou', 'chat', fullname($sender));
c52b4db5
AD
949 } else if ($sender->id == $currentuser->id) { // Something is not caught?
950 // Allow beep for a active chat user only, else user can beep anyone and get fullname.
d0157d82 951 if (!empty($chatuser) && is_numeric($beepwho)) {
c52b4db5
AD
952 $chatusers = chat_get_users($chatuser->chatid, $chatuser->groupid, $groupingid);
953 if (array_key_exists($beepwho, $chatusers)) {
954 $outmain = get_string('messageyoubeep', 'chat', fullname($chatusers[$beepwho]));
955 } else {
956 $outmain = get_string('messageyoubeep', 'chat', $beepwho);
957 }
d0157d82
RT
958 } else {
959 $outmain = get_string('messageyoubeep', 'chat', $beepwho);
960 }
75d07096 961 }
c52b4db5 962 } else if (substr($text, 0, 1) == '/') { // It's a user command.
75d07096 963 $special = true;
964 $result->type = 'command';
75d07096 965 $pattern = '#(^\/)(\w+).*#';
6c6ed54a
FM
966 preg_match($pattern, $text, $matches);
967 $command = isset($matches[2]) ? $matches[2] : false;
968 // Support some IRC commands.
c52b4db5 969 switch ($command) {
6c6ed54a
FM
970 case 'me':
971 $outmain = '*** <b>'.$sender->firstname.' '.substr($text, 4).'</b>';
972 break;
973 default:
974 // Error, we set special back to false to use the classic message output.
975 $special = false;
976 break;
75d07096 977 }
c52b4db5 978 } else if (preg_match($patternto, $text)) {
75d07096 979 $special = true;
980 $result->type = 'dialogue';
6c6ed54a 981 $matches = array();
c52b4db5 982 preg_match($patternto, $text, $matches);
6c6ed54a
FM
983 if (isset($matches[1]) && isset($matches[2])) {
984 $outmain = $sender->firstname.' <b>'.get_string('saidto', 'chat').'</b> <i>'.$matches[1].'</i>: '.$matches[2];
985 } else {
986 // Error, we set special back to false to use the classic message output.
987 $special = false;
988 }
75d07096 989 }
990
6c6ed54a 991 if (!$special) {
75d07096 992 $outmain = $text;
993 }
994
995 $result->text = strip_tags($outtime.': '.$outmain);
996
a2592fec 997 $mymessageclass = '';
75d07096 998 if ($sender->id == $USER->id) {
a2592fec 999 $mymessageclass = 'chat-message-mymessage';
75d07096 1000 }
1001
a2592fec 1002 $senderprofile = $CFG->wwwroot.'/user/view.php?id='.$sender->id.'&amp;course='.$courseid;
c52b4db5
AD
1003 $usermessage = new user_message($senderprofile, fullname($sender), $message->picture,
1004 $mymessageclass, $outtime, $outmain, $theme);
a2592fec
AD
1005
1006 $output = $PAGE->get_renderer('mod_chat');
1007 $result->html = $output->render($usermessage);
1008
c52b4db5 1009 // When user beeps other user, then don't show any timestamp to other users in chat.
d0157d82
RT
1010 if (('' === $outmain) && $special) {
1011 return false;
1012 } else {
1013 return $result;
1014 }
75d07096 1015}
1016
83064f9c 1017/**
1018 * @global object $DB
1019 * @global object $CFG
1020 * @global object $COURSE
1021 * @global object $OUTPUT
1022 * @param object $users
1023 * @param object $course
1024 * @return array return formatted user list
1025 */
1026function chat_format_userlist($users, $course) {
1027 global $CFG, $DB, $COURSE, $OUTPUT;
1028 $result = array();
c52b4db5 1029 foreach ($users as $user) {
83064f9c 1030 $item = array();
1031 $item['name'] = fullname($user);
ff0e58c8 1032 $item['url'] = $CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id;
812dbaf7 1033 $item['picture'] = $OUTPUT->user_picture($user);
83064f9c 1034 $item['id'] = $user->id;
1035 $result[] = $item;
1036 }
1037 return $result;
1038}
1039
1040/**
1041 * Print json format error
1042 * @param string $level
1043 * @param string $msg
1044 */
1045function chat_print_error($level, $msg) {
1046 header('Content-Length: ' . ob_get_length() );
6bdfef5d 1047 $error = new stdClass();
83064f9c 1048 $error->level = $level;
1049 $error->msg = $msg;
1050 $response['error'] = $error;
1051 echo json_encode($response);
1052 ob_end_flush();
1053 exit;
1054}
1055
848bb113 1056/**
b2b4ec30
RT
1057 * List the actions that correspond to a view of this module.
1058 * This is used by the participation report.
1059 *
1060 * Note: This is not used by new logging system. Event with
1061 * crud = 'r' and edulevel = LEVEL_PARTICIPATING will
1062 * be considered as view action.
1063 *
848bb113 1064 * @return array
1065 */
f3221af9 1066function chat_get_view_actions() {
c52b4db5 1067 return array('view', 'view all', 'report');
f3221af9 1068}
1069
848bb113 1070/**
b2b4ec30
RT
1071 * List the actions that correspond to a post of this module.
1072 * This is used by the participation report.
1073 *
1074 * Note: This is not used by new logging system. Event with
1075 * crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING
1076 * will be considered as post action.
1077 *
848bb113 1078 * @return array
1079 */
f3221af9 1080function chat_get_post_actions() {
1081 return array('talk');
1082}
1083
848bb113 1084/**
1085 * @global object
1086 * @global object
1087 * @param array $courses
1088 * @param array $htmlarray Passed by reference
1089 */
9ca0187e 1090function chat_print_overview($courses, &$htmlarray) {
1091 global $USER, $CFG;
1092
1093 if (empty($courses) || !is_array($courses) || count($courses) == 0) {
1094 return array();
1095 }
1096
c52b4db5 1097 if (!$chats = get_all_instances_in_courses('chat', $courses)) {
9ca0187e 1098 return;
1099 }
1100
1101 $strchat = get_string('modulename', 'chat');
1102 $strnextsession = get_string('nextsession', 'chat');
9ca0187e 1103
1104 foreach ($chats as $chat) {
c52b4db5 1105 if ($chat->chattime and $chat->schedule) { // A chat is scheduled.
a2a37336 1106 $str = '<div class="chat overview"><div class="name">'.
c52b4db5 1107 $strchat.': <a '.($chat->visible ? '' : ' class="dimmed"').
a2a37336 1108 ' href="'.$CFG->wwwroot.'/mod/chat/view.php?id='.$chat->coursemodule.'">'.
1109 $chat->name.'</a></div>';
1110 $str .= '<div class="info">'.$strnextsession.': '.userdate($chat->chattime).'</div></div>';
1111
1112 if (empty($htmlarray[$chat->course]['chat'])) {
1113 $htmlarray[$chat->course]['chat'] = $str;
1114 } else {
1115 $htmlarray[$chat->course]['chat'] .= $str;
1116 }
9ca0187e 1117 }
9ca0187e 1118 }
1119}
1120
0b5a80a1 1121
1122/**
1123 * Implementation of the function for printing the form elements that control
1124 * whether the course reset functionality affects the chat.
848bb113 1125 *
1126 * @param object $mform form passed by reference
0b5a80a1 1127 */
1128function chat_reset_course_form_definition(&$mform) {
1129 $mform->addElement('header', 'chatheader', get_string('modulenameplural', 'chat'));
c52b4db5 1130 $mform->addElement('advcheckbox', 'reset_chat', get_string('removemessages', 'chat'));
0b5a80a1 1131}
1132
1133/**
1134 * Course reset form defaults.
848bb113 1135 *
1136 * @param object $course
1137 * @return array
0b5a80a1 1138 */
1139function chat_reset_course_form_defaults($course) {
c52b4db5 1140 return array('reset_chat' => 1);
0b5a80a1 1141}
1142
1143/**
72d2982e 1144 * Actual implementation of the reset course functionality, delete all the
0b5a80a1 1145 * chat messages for course $data->courseid.
848bb113 1146 *
1147 * @global object
1148 * @global object
1149 * @param object $data the data submitted from the reset course.
0b5a80a1 1150 * @return array status array
1151 */
1152function chat_reset_userdata($data) {
d3bf6f92 1153 global $CFG, $DB;
0b5a80a1 1154
1155 $componentstr = get_string('modulenameplural', 'chat');
1156 $status = array();
1157
1158 if (!empty($data->reset_chat)) {
1159 $chatessql = "SELECT ch.id
d3bf6f92 1160 FROM {chat} ch
1161 WHERE ch.course=?";
1162 $params = array($data->courseid);
0b5a80a1 1163
d3bf6f92 1164 $DB->delete_records_select('chat_messages', "chatid IN ($chatessql)", $params);
6e5f40ea 1165 $DB->delete_records_select('chat_messages_current', "chatid IN ($chatessql)", $params);
d3bf6f92 1166 $DB->delete_records_select('chat_users', "chatid IN ($chatessql)", $params);
c52b4db5 1167 $status[] = array('component' => $componentstr, 'item' => get_string('removemessages', 'chat'), 'error' => false);
0b5a80a1 1168 }
1169
c52b4db5 1170 // Updating dates - shift may be negative too.
0b5a80a1 1171 if ($data->timeshift) {
1172 shift_course_mod_dates('chat', array('chattime'), $data->timeshift, $data->courseid);
c52b4db5 1173 $status[] = array('component' => $componentstr, 'item' => get_string('datechanged'), 'error' => false);
0b5a80a1 1174 }
1175
1176 return $status;
1177}
1178
f432bebf 1179/**
1180 * Returns all other caps used in module
848bb113 1181 *
1182 * @return array
f432bebf 1183 */
1184function chat_get_extra_capabilities() {
1185 return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames');
1186}
1187
47cfd331 1188
42f103be 1189/**
1190 * @param string $feature FEATURE_xx constant for requested feature
1191 * @return mixed True if module supports feature, null if doesn't know
1192 */
1193function chat_supports($feature) {
1194 switch($feature) {
c52b4db5
AD
1195 case FEATURE_GROUPS:
1196 return true;
1197 case FEATURE_GROUPINGS:
1198 return true;
c52b4db5
AD
1199 case FEATURE_MOD_INTRO:
1200 return true;
1201 case FEATURE_BACKUP_MOODLE2:
1202 return true;
1203 case FEATURE_COMPLETION_TRACKS_VIEWS:
1204 return true;
1205 case FEATURE_GRADE_HAS_GRADE:
1206 return false;
1207 case FEATURE_GRADE_OUTCOMES:
1208 return true;
1209 case FEATURE_SHOW_DESCRIPTION:
1210 return true;
1211 default:
1212 return null;
42f103be 1213 }
1214}
b14ae498 1215
1216function chat_extend_navigation($navigation, $course, $module, $cm) {
36ab2fed 1217 global $CFG;
0b29477b
SH
1218
1219 $currentgroup = groups_get_activity_group($cm, true);
4f0c2d00 1220
6536217c 1221 if (has_capability('mod/chat:chat', context_module::instance($cm->id))) {
b14ae498 1222 $strenterchat = get_string('enterchat', 'chat');
b14ae498 1223
1224 $target = $CFG->wwwroot.'/mod/chat/';
c52b4db5 1225 $params = array('id' => $cm->instance);
b14ae498 1226
1227 if ($currentgroup) {
1228 $params['groupid'] = $currentgroup;
1229 }
1230
1231 $links = array();
e7521559 1232
36ab2fed 1233 $url = new moodle_url($target.'gui_'.$CFG->chat_method.'/index.php', $params);
c52b4db5
AD
1234 $action = new popup_action('click', $url, 'chat'.$course->id.$cm->instance.$currentgroup,
1235 array('height' => 500, 'width' => 700));
36ab2fed 1236 $links[] = new action_link($url, $strenterchat, $action);
b14ae498 1237
af140288 1238 $url = new moodle_url($target.'gui_basic/index.php', $params);
c52b4db5
AD
1239 $action = new popup_action('click', $url, 'chat'.$course->id.$cm->instance.$currentgroup,
1240 array('height' => 500, 'width' => 700));
af140288 1241 $links[] = new action_link($url, get_string('noframesjs', 'message'), $action);
b14ae498 1242
1243 foreach ($links as $link) {
c52b4db5 1244 $navigation->add($link->text, $link, navigation_node::TYPE_SETTING, null , null, new pix_icon('i/group' , ''));
b14ae498 1245 }
1246 }
1247
1248 $chatusers = chat_get_users($cm->instance, $currentgroup, $cm->groupingid);
c52b4db5 1249 if (is_array($chatusers) && count($chatusers) > 0) {
3406acde 1250 $users = $navigation->add(get_string('currentusers', 'chat'));
b14ae498 1251 foreach ($chatusers as $chatuser) {
c52b4db5
AD
1252 $userlink = new moodle_url('/user/view.php', array('id' => $chatuser->id, 'course' => $course->id));
1253 $users->add(fullname($chatuser).' '.format_time(time() - $chatuser->lastmessageping),
1254 $userlink, navigation_node::TYPE_USER, null, null, new pix_icon('i/user', ''));
b14ae498 1255 }
1256 }
1257}
1258
0b29477b
SH
1259/**
1260 * Adds module specific settings to the settings block
1261 *
1262 * @param settings_navigation $settings The settings navigation object
1263 * @param navigation_node $chatnode The node to add module settings to
1264 */
1265function chat_extend_settings_navigation(settings_navigation $settings, navigation_node $chatnode) {
1266 global $DB, $PAGE, $USER;
b14ae498 1267 $chat = $DB->get_record("chat", array("id" => $PAGE->cm->instance));
0b29477b 1268
b14ae498 1269 if ($chat->chattime && $chat->schedule) {
c52b4db5
AD
1270 $nextsessionnode = $chatnode->add(get_string('nextsession', 'chat').
1271 ': '.userdate($chat->chattime).
1c2a11fc 1272 ' ('.usertimezone($USER->timezone).')');
3406acde 1273 $nextsessionnode->add_class('note');
b14ae498 1274 }
1275
1276 $currentgroup = groups_get_activity_group($PAGE->cm, true);
1277 if ($currentgroup) {
1278 $groupselect = " AND groupid = '$currentgroup'";
1279 } else {
1280 $groupselect = '';
1281 }
1282
c52b4db5 1283 if ($chat->studentlogs || has_capability('mod/chat:readlog', $PAGE->cm->context)) {
b14ae498 1284 if ($DB->get_records_select('chat_messages', "chatid = ? $groupselect", array($chat->id))) {
c52b4db5 1285 $chatnode->add(get_string('viewreport', 'chat'), new moodle_url('/mod/chat/report.php', array('id' => $PAGE->cm->id)));
b14ae498 1286 }
1287 }
50d76994 1288}
a8e3b008
DC
1289
1290/**
1291 * user logout event handler
1292 *
c8135e8b
FM
1293 * @param \core\event\user_loggedout $event The event.
1294 * @return void
a8e3b008 1295 */
c8135e8b 1296function chat_user_logout(\core\event\user_loggedout $event) {
a8e3b008 1297 global $DB;
c8135e8b 1298 $DB->delete_records('chat_users', array('userid' => $event->objectid));
a8e3b008 1299}
b1627a92
DC
1300
1301/**
1302 * Return a list of page types
1303 * @param string $pagetype current page type
1304 * @param stdClass $parentcontext Block's parent context
1305 * @param stdClass $currentcontext Current context of block
1306 */
b38e2e28 1307function chat_page_type_list($pagetype, $parentcontext, $currentcontext) {
c52b4db5
AD
1308 $modulepagetype = array('mod-chat-*' => get_string('page-mod-chat-x', 'chat'));
1309 return $modulepagetype;
b1627a92 1310}
8380bc7f
JL
1311
1312/**
1313 * Return a list of the latest messages in the given chat session.
1314 *
1315 * @param stdClass $chatuser chat user session data
1316 * @param int $chatlasttime last time messages were retrieved
1317 * @return array list of messages
1318 * @since Moodle 3.0
1319 */
1320function chat_get_latest_messages($chatuser, $chatlasttime) {
1321 global $DB;
1322
1323 $params = array('groupid' => $chatuser->groupid, 'chatid' => $chatuser->chatid, 'lasttime' => $chatlasttime);
1324
1325 $groupselect = $chatuser->groupid ? " AND (groupid=" . $chatuser->groupid . " OR groupid=0) " : "";
1326
1327 return $DB->get_records_select('chat_messages_current', 'chatid = :chatid AND timestamp > :lasttime ' . $groupselect,
1328 $params, 'timestamp ASC');
1329}
5841b9d5
JL
1330
1331/**
1332 * Mark the activity completed (if required) and trigger the course_module_viewed event.
1333 *
1334 * @param stdClass $chat chat object
1335 * @param stdClass $course course object
1336 * @param stdClass $cm course module object
1337 * @param stdClass $context context object
1338 * @since Moodle 3.0
1339 */
1340function chat_view($chat, $course, $cm, $context) {
1341
1342 // Trigger course_module_viewed event.
1343 $params = array(
1344 'context' => $context,
1345 'objectid' => $chat->id
1346 );
1347
1348 $event = \mod_chat\event\course_module_viewed::create($params);
1349 $event->add_record_snapshot('course_modules', $cm);
1350 $event->add_record_snapshot('course', $course);
1351 $event->add_record_snapshot('chat', $chat);
1352 $event->trigger();
1353
1354 // Completion.
1355 $completion = new completion_info($course);
1356 $completion->set_module_viewed($cm);
1357}