CHAT_MOD/MDL-14651, auto-scrolling support
[moodle.git] / mod / chat / lib.php
CommitLineData
1c61c8d6 1<?php // $Id$
1515a89e 2
3/// Library of functions and constants for module chat
c4d588cc 4require_once($CFG->libdir.'/pagelib.php');
5
111e78d6 6$CFG->chat_enable_ajax = false;
1d507186 7$CFG->chat_ajax_debug = false;
8$CFG->chat_use_cache = false;
9
1515a89e 10// The HTML head for the message window to start with (<!-- nix --> is used to get some browsers starting with output
1f8abb89 11$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 12
13// The HTML head for the message window to start with (with js scrolling)
1f8abb89 14$CHAT_HTMLHEAD_JS = <<<EOD
15<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
16<html><head><script type="text/javascript">
17//<![CDATA[
18function move(){
19 if (scroll_active)
20 window.scroll(1,400000);
21 window.setTimeout("move()",100);
22}
23var scroll_active = true;
24move();
25//]]>
26</script>
27</head>
28<body onBlur="scroll_active = true" onFocus="scroll_active = false">
29EOD;
30$CHAT_HTMLHEAD_JS .= padding(200);
1515a89e 31
32// The HTML code for standard empty pages (e.g. if a user was kicked out)
1f8abb89 33$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 34
35// The HTML head for the message input page
1f8abb89 36$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 37
38// The HTML code for the message input page, with JavaScript
1d507186 39$CHAT_HTMLHEAD_MSGINPUT_JS = <<<EOD
40<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
41<html>
42 <head><title>Message Input</title>
43 <script type="text/javascript">
44 //<![CDATA[
45 scroll_active = true;
46 function empty_field_and_submit(){
47 document.fdummy.arsc_message.value=document.f.arsc_message.value;
48 document.fdummy.submit();
49 document.f.arsc_message.focus();
50 document.f.arsc_message.select();
51 return false;
52 }
53 //]]>
54 </script>
55 </head><body OnLoad="document.f.arsc_message.focus();document.f.arsc_message.select();">;
56EOD;
1515a89e 57
fbabbd23 58// Dummy data that gets output to the browser as needed, in order to make it show output
6e5f40ea 59$CHAT_DUMMY_DATA = padding(200);
5c2f6a7f 60
6e5f40ea 61function padding($n){
5c2f6a7f 62 $str = '';
633c3341 63 for($i=0; $i<$n; $i++){
1f8abb89 64 $str.="<!-- nix -->\n";
5c2f6a7f 65 }
66 return $str;
67}
1515a89e 68
69function chat_add_instance($chat) {
c18269c7 70 global $DB;
b5de723d 71/// Given an object containing all the necessary data,
7cac0c4b 72/// (defined by the form in mod_form.php) this function
b5de723d 73/// will create a new instance and return the id number
1515a89e 74/// of the new instance.
75
76 $chat->timemodified = time();
77
c18269c7 78 if ($returnid = $DB->insert_record("chat", $chat)) {
8496c4af 79
80 $event = NULL;
81 $event->name = $chat->name;
82 $event->description = $chat->intro;
83 $event->courseid = $chat->course;
84 $event->groupid = 0;
85 $event->userid = 0;
86 $event->modulename = 'chat';
87 $event->instance = $returnid;
88 $event->eventtype = $chat->schedule;
89 $event->timestart = $chat->chattime;
90 $event->timeduration = 0;
91
92 add_event($event);
93 }
94
95 return $returnid;
1515a89e 96}
97
98
99function chat_update_instance($chat) {
c18269c7 100 global $DB;
b5de723d 101/// Given an object containing all the necessary data,
7cac0c4b 102/// (defined by the form in mod_form.php) this function
1515a89e 103/// will update an existing instance with new data.
104
105 $chat->timemodified = time();
106 $chat->id = $chat->instance;
107
1515a89e 108
c18269c7 109 if ($returnid = $DB->update_record("chat", $chat)) {
8496c4af 110
264867fd 111 $event = new object();
8496c4af 112
c18269c7 113 if ($event->id = $DB->get_field('event', 'id', array('modulename'=>'chat', 'instance'=>$chat->id))) {
8496c4af 114
115 $event->name = $chat->name;
116 $event->description = $chat->intro;
117 $event->timestart = $chat->chattime;
118
119 update_event($event);
120 }
121 }
122
123 return $returnid;
1515a89e 124}
125
126
127function chat_delete_instance($id) {
c18269c7 128 global $DB;
b5de723d 129/// Given an ID of an instance of this module,
130/// this function will permanently delete the instance
131/// and any data that depends on it.
1515a89e 132
c18269c7 133 if (! $chat = $DB->get_record('chat', array('id'=>$id))) {
1515a89e 134 return false;
135 }
136
137 $result = true;
138
139 # Delete any dependent records here #
140
c18269c7 141 if (! $DB->delete_records('chat', array('id'=>$chat->id))) {
a71efae3 142 $result = false;
143 }
c18269c7 144 if (! $DB->delete_records('chat_messages', array('chatid'=>$chat->id))) {
a71efae3 145 $result = false;
146 }
6e5f40ea 147 if (! $DB->delete_records('chat_messages_current', array('chatid'=>$chat->id))) {
148 $result = false;
149 }
c18269c7 150 if (! $DB->delete_records('chat_users', array('chatid'=>$chat->id))) {
1515a89e 151 $result = false;
152 }
153
880d8675 154 $pagetypes = page_import_types('mod/chat/');
155 foreach($pagetypes as $pagetype) {
c18269c7 156 if (!$DB->delete_records('block_instance', array('pageid'=>$chat->id, 'pagetype'=>$pagetype))) {
880d8675 157 $result = false;
158 }
159 }
160
c18269c7 161 if (! $DB->delete_records('event', array('modulename'=>'chat', 'instance'=>$chat->id))) {
36eb856f 162 $result = false;
163 }
164
1515a89e 165 return $result;
166}
167
168function chat_user_outline($course, $user, $mod, $chat) {
b5de723d 169/// Return a small object with summary information about what a
1515a89e 170/// user has done with a given particular instance of this module
171/// Used for user activity reports.
172/// $return->time = the time they did it
173/// $return->info = a short text description
d3bf6f92 174 return NULL;
1515a89e 175}
176
177function chat_user_complete($course, $user, $mod, $chat) {
b5de723d 178/// Print a detailed representation of what a user has done with
1515a89e 179/// a given particular instance of this module, for user activity reports.
1515a89e 180 return true;
181}
182
dd97c328 183function chat_print_recent_activity($course, $viewfullnames, $timestart) {
184/// Given a course and a date, prints a summary of all chat rooms past and present
1515a89e 185/// This function is called from course/lib.php: print_recent_activity()
d3bf6f92 186 global $CFG, $USER, $DB;
dd97c328 187
188 // this is approximate only, but it is really fast ;-)
189 $timeout = $CFG->chat_old_ping * 10;
190
d3bf6f92 191 if (!$mcms = $DB->get_records_sql("SELECT cm.id, MAX(chm.timestamp) AS lasttime
192 FROM {course_modules} cm
193 JOIN {modules} md ON md.id = cm.module
194 JOIN {chat} ch ON ch.id = cm.instance
195 JOIN {chat_messages} chm ON chm.chatid = ch.id
196 WHERE chm.timestamp > ? AND ch.course = ? AND md.name = 'chat'
197 GROUP BY cm.id
198 ORDER BY lasttime ASC", array($timestart, $course->id))) {
dd97c328 199 return false;
200 }
201
202 $past = array();
203 $current = array();
204 $modinfo =& get_fast_modinfo($course); // reference needed because we might load the groups
205
fd4d41c3 206 foreach ($mcms as $cmid=>$mcm) {
207 if (!array_key_exists($cmid, $modinfo->cms)) {
dd97c328 208 continue;
209 }
fd4d41c3 210 $cm = $modinfo->cms[$cmid];
211 $cm->lasttime = $mcm->lasttime;
dd97c328 212 if (!$modinfo->cms[$cm->id]->uservisible) {
213 continue;
214 }
b7602a11 215
dd97c328 216 if (groups_get_activity_groupmode($cm) != SEPARATEGROUPS
217 or has_capability('moodle/site:accessallgroups', get_context_instance(CONTEXT_MODULE, $cm->id))) {
218 if ($timeout > time() - $cm->lasttime) {
219 $current[] = $cm;
220 } else {
221 $past[] = $cm;
222 }
223
224 continue;
225 }
226
227 if (is_null($modinfo->groups)) {
228 $modinfo->groups = groups_get_user_groups($course->id); // load all my groups and cache it in modinfo
229 }
c5a05b95 230
dd97c328 231 // verify groups in separate mode
232 if (!$mygroupids = $modinfo->groups[$cm->groupingid]) {
233 continue;
234 }
0469cccf 235
dd97c328 236 // ok, last post was not for my group - we have to query db to get last message from one of my groups
237 // only minor problem is that the order will not be correct
238 $mygroupids = implode(',', $mygroupids);
239 $cm->mygroupids = $mygroupids;
240
d3bf6f92 241 if (!$mcm = $DB->get_record_sql("SELECT cm.id, MAX(chm.timestamp) AS lasttime
242 FROM {course_modules} cm
243 JOIN {chat} ch ON ch.id = cm.instance
6e5f40ea 244 JOIN {chat_messages_current} chm ON chm.chatid = ch.id
d3bf6f92 245 WHERE chm.timestamp > ? AND cm.id = ? AND
246 (chm.groupid IN ($mygroupids) OR chm.groupid = 0)
247 GROUP BY cm.id", array($timestart, $cm->id))) {
dd97c328 248 continue;
249 }
fd4d41c3 250
251 $cm->lasttime = $mcm->lasttime;
dd97c328 252 if ($timeout > time() - $cm->lasttime) {
253 $current[] = $cm;
254 } else {
255 $past[] = $cm;
256 }
257 }
258
259 if (!$past and !$current) {
b7602a11 260 return false;
261 }
1515a89e 262
dd97c328 263 $strftimerecent = get_string('strftimerecent');
264
265 if ($past) {
266 print_headline(get_string('pastchats', 'chat').':');
267
268 foreach ($past as $cm) {
269 $link = $CFG->wwwroot.'/mod/chat/view.php?id='.$cm->id;
270 $date = userdate($cm->lasttime, $strftimerecent);
271 echo '<div class="head"><div class="date">'.$date.'</div></div>';
272 echo '<div class="info"><a href="'.$link.'">'.format_string($cm->name,true).'</a></div>';
b7602a11 273 }
8f7dc7f1 274 }
275
276 if ($current) {
dd97c328 277 print_headline(get_string('currentchats', 'chat').':');
278
279 $oldest = floor((time()-$CFG->chat_old_ping)/10)*10; // better db caching
280
281 $timeold = time() - $CFG->chat_old_ping;
282 $timeold = floor($timeold/10)*10; // better db caching
283 $timeoldext = time() - ($CFG->chat_old_ping*10); // JSless gui_basic needs much longer timeouts
284 $timeoldext = floor($timeoldext/10)*10; // better db caching
285
d3bf6f92 286 $params = array('timeold'=>$timeold, 'timeoldext'=>$timeoldext, 'cmid'=>$cm->id);
287
288 $timeout = "AND (chu.version<>'basic' AND chu.lastping>:timeold) OR (chu.version='basic' AND chu.lastping>:timeoldext)";
dd97c328 289
290 foreach ($current as $cm) {
291 //count users first
292 if (isset($cm->mygroupids)) {
293 $groupselect = "AND (chu.groupid IN ({$cm->mygroupids}) OR chu.groupid = 0)";
294 } else {
295 $groupselect = "";
296 }
fd4d41c3 297
d3bf6f92 298 if (!$users = $DB->get_records_sql("SELECT u.id, u.firstname, u.lastname, u.email, u.picture
299 FROM {course_modules} cm
300 JOIN {chat} ch ON ch.id = cm.instance
301 JOIN {chat_users} chu ON chu.chatid = ch.id
302 JOIN {user} u ON u.id = chu.userid
303 WHERE cm.id = :cmid $timeout $groupselect
304 GROUP BY u.id, u.firstname, u.lastname, u.email, u.picture", $params)) {
dd97c328 305 }
306
307 $link = $CFG->wwwroot.'/mod/chat/view.php?id='.$cm->id;
308 $date = userdate($cm->lasttime, $strftimerecent);
309
310 echo '<div class="head"><div class="date">'.$date.'</div></div>';
311 echo '<div class="info"><a href="'.$link.'">'.format_string($cm->name,true).'</a></div>';
312 echo '<div class="userlist">';
313 if ($users) {
314 echo '<ul>';
315 foreach ($users as $user) {
316 echo '<li>'.fullname($user, $viewfullnames).'</li>';
317 }
318 echo '</ul>';
319 }
320 echo '</div>';
321 }
b7602a11 322 }
323
324 return true;
1515a89e 325}
326
8f7dc7f1 327
1515a89e 328function chat_cron () {
329/// Function to be run periodically according to the moodle cron
b5de723d 330/// This function searches for things that need to be done, such
331/// as sending out mail, toggling flags etc ...
d3bf6f92 332 global $DB;
1515a89e 333
fcd3a1ee 334 chat_update_chat_times();
335
7d792369 336 chat_delete_old_users();
337
319038c3 338 /// Delete old messages with a
339 /// single SQL query.
340 $subselect = "SELECT c.keepdays
d3bf6f92 341 FROM {chat} c
342 WHERE c.id = {chat_messages}.chatid";
4388027c 343
319038c3 344 $sql = "DELETE
d3bf6f92 345 FROM {chat_messages}
6e5f40ea 346 WHERE ($subselect) > 0 AND timestamp < ( ".time()." -($subselect) * 24 * 3600)";
347
348 $DB->execute($sql);
349
350 $sql = "DELETE
351 FROM {chat_messages_current}
352 WHERE timestamp < ( ".time()." - 8 * 3600)";
4388027c 353
d3bf6f92 354 $DB->execute($sql);
22a4491a 355
1515a89e 356 return true;
357}
358
84a2fdd7 359function chat_get_participants($chatid, $groupid=0) {
05855091 360//Returns the users with data in one chat
361//(users with records in chat_messages, students)
d3bf6f92 362 global $DB;
05855091 363
d3bf6f92 364 $params = array('groupid'=>$groupid, 'chatid'=>$chatid);
05855091 365
84a2fdd7 366 if ($groupid) {
d3bf6f92 367 $groupselect = " AND (c.groupid=:groupid OR c.groupid='0')";
84a2fdd7 368 } else {
369 $groupselect = "";
370 }
371
05855091 372 //Get students
d3bf6f92 373 $students = $DB->get_records_sql("SELECT DISTINCT u.id, u.id
374 FROM {user} u, {chat_messages} c
375 WHERE c.chatid = :chatid $groupselect
376 AND u.id = c.userid", $params);
1515a89e 377
05855091 378 //Return students array (it contains an array of unique users)
379 return ($students);
380}
1515a89e 381
8496c4af 382function chat_refresh_events($courseid = 0) {
383// This standard function will check all instances of this module
384// and make sure there are up-to-date events created for each of them.
385// If courseid = 0, then every chat event in the site is checked, else
386// only chat events belonging to the course specified are checked.
387// This function is used, in its new format, by restore_refresh_events()
d3bf6f92 388 global $DB;
8496c4af 389
390 if ($courseid) {
d3bf6f92 391 if (! $chats = $DB->get_records("chat", array("course"=>$courseid))) {
8496c4af 392 return true;
393 }
394 } else {
d3bf6f92 395 if (! $chats = $DB->get_records("chat")) {
8496c4af 396 return true;
397 }
398 }
d3bf6f92 399 $moduleid = $DB->get_field('modules', 'id', array('name'=>'chat'));
8496c4af 400
401 foreach ($chats as $chat) {
402 $event = NULL;
d3bf6f92 403 $event->name = $chat->name;
404 $event->description = $chat->intro;
8496c4af 405 $event->timestart = $chat->chattime;
406
d3bf6f92 407 if ($event->id = $DB->get_field('event', 'id', array('modulename'=>'chat', 'instance'=>$chat->id))) {
8496c4af 408 update_event($event);
409
410 } else {
411 $event->courseid = $chat->course;
412 $event->groupid = 0;
413 $event->userid = 0;
414 $event->modulename = 'chat';
415 $event->instance = $chat->id;
416 $event->eventtype = $chat->schedule;
417 $event->timeduration = 0;
d3bf6f92 418 $event->visible = $DB->get_field('course_modules', 'visible', array('module'=>$moduleid, 'instance'=>$chat->id));
b5de723d 419
8496c4af 420 add_event($event);
421 }
422 }
423 return true;
424}
425
516121bd 426
1515a89e 427//////////////////////////////////////////////////////////////////////
428/// Functions that require some SQL
429
a12e11c1 430function chat_get_users($chatid, $groupid=0, $groupingid=0) {
d3bf6f92 431 global $DB;
1515a89e 432
d3bf6f92 433 $params = array('chatid'=>$chatid, 'groupid'=>$groupid, 'groupingid'=>$groupingid);
84a2fdd7 434
435 if ($groupid) {
d3bf6f92 436 $groupselect = " AND (c.groupid=:groupid OR c.groupid='0')";
84a2fdd7 437 } else {
438 $groupselect = "";
439 }
6e5f40ea 440
a12e11c1 441 if (!empty($CFG->enablegroupings) && !(empty($groupingid))) {
d3bf6f92 442 $groupingjoin = "JOIN {groups_members} gm ON u.id = gm.userid
443 JOIN {groupings_groups} gg ON gm.groupid = gg.groupid AND gg.groupingid = :groupingid ";
6e5f40ea 444
a12e11c1 445 } else {
446 $groupingjoin = '';
447 }
b5de723d 448
d3bf6f92 449 return $DB->get_records_sql("SELECT DISTINCT u.id, u.firstname, u.lastname, u.picture, c.lastmessageping, c.firstping, u.imagealt
450 FROM {chat_users} c
451 JOIN {user} u ON u.id = c.userid
452 $groupingjoin
453 WHERE c.chatid = :chatid
454 $groupselect
455 ORDER BY c.firstping ASC", $params);
1515a89e 456}
457
84a2fdd7 458function chat_get_latest_message($chatid, $groupid=0) {
f33e1ed4 459 global $DB;
1515a89e 460
d3bf6f92 461 $params = array('chatid'=>$chatid, 'groupid'=>$groupid);
1515a89e 462
84a2fdd7 463 if ($groupid) {
d3bf6f92 464 $groupselect = "AND (groupid=:groupid OR groupid=0)";
84a2fdd7 465 } else {
466 $groupselect = "";
467 }
468
f33e1ed4 469 $sql = "SELECT *
6e5f40ea 470 FROM {chat_messages_current}
d3bf6f92 471 WHERE chatid = :chatid
f33e1ed4 472 $groupselect
473 ORDER BY timestamp DESC";
03cedd62 474
f33e1ed4 475 return $DB->get_record_sql($sql, $params, true);
1515a89e 476}
477
5a8625e4 478
1515a89e 479//////////////////////////////////////////////////////////////////////
516121bd 480// login if not already logged in
1515a89e 481
a32c7772 482function chat_login_user($chatid, $version, $groupid, $course) {
d3bf6f92 483 global $USER, $DB;
484
485 if (($version != 'sockets') and $chatuser = $DB->get_record('chat_users', array('chatid'=>$chatid, 'userid'=>$USER->id, 'groupid'=>$groupid))) {
516121bd 486 $chatuser->version = $version;
d96466d2 487 $chatuser->ip = $USER->lastip;
516121bd 488 $chatuser->lastping = time();
489 $chatuser->lang = current_language();
1515a89e 490
d96466d2 491 // Sometimes $USER->lastip is not setup properly
d13ef2fb 492 // during login. Update with current value if possible
f83edcb1 493 // or provide a dummy value for the db
d13ef2fb 494 if (empty($chatuser->ip)) {
495 $chatuser->ip = getremoteaddr();
496 if (empty($chatuser->ip)) {
f83edcb1 497 $chatuser->ip = '';
d13ef2fb 498 }
499 }
500
516121bd 501 if (($chatuser->course != $course->id)
502 or ($chatuser->userid != $USER->id)) {
503 return false;
504 }
d3bf6f92 505 if (!$DB->update_record('chat_users', $chatuser)) {
516121bd 506 return false;
507 }
516121bd 508 } else {
6ee78cee 509 $chatuser = new object();
516121bd 510 $chatuser->chatid = $chatid;
511 $chatuser->userid = $USER->id;
512 $chatuser->groupid = $groupid;
513 $chatuser->version = $version;
d96466d2 514 $chatuser->ip = $USER->lastip;
516121bd 515 $chatuser->lastping = $chatuser->firstping = $chatuser->lastmessageping = time();
516 $chatuser->sid = random_string(32);
3dfd307f 517 $chatuser->course = $course->id; //caching - needed for current_language too
518 $chatuser->lang = current_language(); //caching - to resource intensive to find out later
516121bd 519
d96466d2 520 // Sometimes $USER->lastip is not setup properly
274f0091 521 // during login. Update with current value if possible
522 // or provide a dummy value for the db
523 if (empty($chatuser->ip)) {
524 $chatuser->ip = getremoteaddr();
525 if (empty($chatuser->ip)) {
526 $chatuser->ip = '';
527 }
528 }
529
530
d3bf6f92 531 if (!$DB->insert_record('chat_users', $chatuser)) {
516121bd 532 return false;
533 }
534
a32c7772 535 if ($version == 'sockets') {
536 // do not send 'enter' message, chatd will do it
537 } else {
6ee78cee 538 $message = new object();
2ac0d13b 539 $message->chatid = $chatuser->chatid;
540 $message->userid = $chatuser->userid;
541 $message->groupid = $groupid;
542 $message->message = 'enter';
543 $message->system = 1;
544 $message->timestamp = time();
545
6e5f40ea 546 if (!$DB->insert_record('chat_messages', $message) || !$DB->insert_record('chat_messages_current', $message)) {
2f52a088 547 print_error('cantinsert', 'chat');
2ac0d13b 548 }
516121bd 549 }
1515a89e 550 }
551
552 return $chatuser->sid;
553}
554
7d792369 555function chat_delete_old_users() {
556// Delete the old and in the way
d3bf6f92 557 global $CFG, $DB;
b5012f3e 558
e7fbd0b3 559 $timeold = time() - $CFG->chat_old_ping;
953eb6f3 560 $timeoldext = time() - ($CFG->chat_old_ping*10); // JSless gui_basic needs much longer timeouts
a32c7772 561
d3bf6f92 562 $query = "(version<>'basic' AND lastping<?) OR (version='basic' AND lastping<?)";
563 $params = array($timeold, $timeoldext);
7d792369 564
d3bf6f92 565 if ($oldusers = $DB->get_records_select('chat_users', $query, $params) ) {
566 $DB->delete_records_select('chat_users', $query, $params);
7d792369 567 foreach ($oldusers as $olduser) {
6ee78cee 568 $message = new object();
516121bd 569 $message->chatid = $olduser->chatid;
570 $message->userid = $olduser->userid;
571 $message->groupid = $olduser->groupid;
572 $message->message = 'exit';
573 $message->system = 1;
7d792369 574 $message->timestamp = time();
b5de723d 575
6e5f40ea 576 if (!$DB->insert_record('chat_messages', $message) || !$DB->insert_record('chat_messages_current', $message) ) {
2f52a088 577 print_error('cantinsert', 'chat');
7d792369 578 }
579 }
580 }
581}
1515a89e 582
22a4491a 583
fcd3a1ee 584function chat_update_chat_times($chatid=0) {
585/// Updates chat records so that the next chat time is correct
d3bf6f92 586 global $DB;
fcd3a1ee 587
588 $timenow = time();
d3bf6f92 589
590 $params = array('timenow'=>$timenow, 'chatid'=>$chatid);
591
fcd3a1ee 592 if ($chatid) {
d3bf6f92 593 if (!$chats[] = $DB->get_record_select("chat", "id = :chatid AND chattime <= :timenow AND schedule > 0", $params)) {
fcd3a1ee 594 return;
595 }
596 } else {
d3bf6f92 597 if (!$chats = $DB->get_records_select("chat", "chattime <= :timenow AND schedule > 0", $params)) {
fcd3a1ee 598 return;
599 }
600 }
601
602 foreach ($chats as $chat) {
7626969c 603 unset($chat->name);
604 unset($chat->intro);
fcd3a1ee 605 switch ($chat->schedule) {
606 case 1: // Single event - turn off schedule and disable
607 $chat->chattime = 0;
608 $chat->schedule = 0;
609 break;
610 case 2: // Repeat daily
f0d3bb9e 611 while ($chat->chattime <= $timenow) {
612 $chat->chattime += 24 * 3600;
613 }
fcd3a1ee 614 break;
615 case 3: // Repeat weekly
f0d3bb9e 616 while ($chat->chattime <= $timenow) {
617 $chat->chattime += 7 * 24 * 3600;
618 }
fcd3a1ee 619 break;
620 }
d3bf6f92 621 $DB->update_record("chat", $chat);
622
623 $event = new object(); // Update calendar too
8496c4af 624
d3bf6f92 625 $cond = "modulename='chat' AND instance = :chatid AND timestart <> :chattime";
626 $params = array('chattime'=>$chat->chattime, 'chatid'=>$chatid);
627
628 if ($event->id = $DB->get_field_select('event', 'id', $cond, $params)) {
8496c4af 629 $event->timestart = $chat->chattime;
630 update_event($event);
631 }
fcd3a1ee 632 }
633}
634
635
aa5c32fd 636function chat_format_message_manually($message, $courseid, $sender, $currentuser, $chat_lastrow=NULL) {
72989350 637 global $CFG, $USER;
1515a89e 638
6ee78cee 639 $output = new object();
516121bd 640 $output->beep = false; // by default
641 $output->refreshusers = false; // by default
7d792369 642
72989350 643 // Use get_user_timezone() to find the correct timezone for displaying this message:
644 // It's either the current user's timezone or else decided by some Moodle config setting
970f144e 645 // First, "reset" $USER->timezone (which could have been set by a previous call to here)
646 // because otherwise the value for the previous $currentuser will take precedence over $CFG->timezone
647 $USER->timezone = 99;
72989350 648 $tz = get_user_timezone($currentuser->timezone);
b5de723d 649
72989350 650 // Before formatting the message time string, set $USER->timezone to the above.
651 // This will allow dst_offset_on (called by userdate) to work correctly, otherwise the
652 // message times appear off because DST is not taken into account when it should be.
653 $USER->timezone = $tz;
b5de723d 654 $message->strtime = userdate($message->timestamp, get_string('strftimemessage', 'chat'), $tz);
655
656 $message->picture = print_user_picture($sender->id, 0, $sender->picture, false, true, false);
582de679 657 if ($courseid) {
d3981e38 658 $message->picture = "<a onclick=\"window.open('$CFG->wwwroot/user/view.php?id=$sender->id&amp;course=$courseid')\" href=\"$CFG->wwwroot/user/view.php?id=$sender->id&amp;course=$courseid\">$message->picture</a>";
582de679 659 }
1515a89e 660
aa5c32fd 661 //Calculate the row class
662 if ($chat_lastrow !== NULL) {
663 $rowclass = ' class="r'.$chat_lastrow.'" ';
664 } else {
665 $rowclass = '';
666 }
667
b5de723d 668 // Start processing the message
1515a89e 669
b5de723d 670 if(!empty($message->system)) {
671 // System event
672 $output->text = $message->strtime.': '.get_string('message'.$message->message, 'chat', fullname($sender));
aa5c32fd 673 $output->html = '<table class="chat-event"><tr'.$rowclass.'><td class="picture">'.$message->picture.'</td><td class="text">';
674 $output->html .= '<span class="event">'.$output->text.'</span></td></tr></table>';
6e5f40ea 675 $output->basic = '<dl><dt class="event">'.$message->strtime.': '.get_string('message'.$message->message, 'chat', fullname($sender)).'</dt></dl>';
7d792369 676
516121bd 677 if($message->message == 'exit' or $message->message == 'enter') {
678 $output->refreshusers = true; //force user panel refresh ASAP
679 }
1515a89e 680 return $output;
681 }
682
82a524ef 683 // It's not a system event
b5de723d 684
685 $text = $message->message;
82a524ef 686
687 /// Parse the text to clean and filter it
688
6ee78cee 689 $options = new object();
82a524ef 690 $options->para = false;
691 $text = format_text($text, FORMAT_MOODLE, $options, $courseid);
927a7808 692
b5de723d 693 // And now check for special cases
927a7808 694 $special = false;
695
b5de723d 696 if (substr($text, 0, 5) == 'beep ') {
6e5f40ea 697 /// It's a beep!
927a7808 698 $special = true;
7d792369 699 $beepwho = trim(substr($text, 5));
9f85bed4 700
b5de723d 701 if ($beepwho == 'all') { // everyone
702 $outinfo = $message->strtime.': '.get_string('messagebeepseveryone', 'chat', fullname($sender));
703 $outmain = '';
704 $output->beep = true; // (eventually this should be set to
7d792369 705 // to a filename uploaded by the user)
706
82a524ef 707 } else if ($beepwho == $currentuser->id) { // current user
b5de723d 708 $outinfo = $message->strtime.': '.get_string('messagebeepsyou', 'chat', fullname($sender));
709 $outmain = '';
7d792369 710 $output->beep = true;
264867fd 711
0eda0a46 712 } else { //something is not caught?
7d792369 713 return false;
714 }
b5de723d 715 } else if (substr($text, 0, 1) == '/') { /// It's a user command
1d507186 716 // support some IRC commands
717 $pattern = '#(^\/)(\w+).*#';
718 preg_match($pattern, trim($text), $matches);
719 $command = $matches[2];
720 switch ($command){
721 case 'me':
927a7808 722 $special = true;
b5de723d 723 $outinfo = $message->strtime;
1d507186 724 $outmain = '*** <b>'.$sender->firstname.' '.substr($text, 4).'</b>';
725 break;
1515a89e 726 }
927a7808 727 }
9f85bed4 728
927a7808 729 if(!$special) {
b5de723d 730 $outinfo = $message->strtime.' '.$sender->firstname;
7d792369 731 $outmain = $text;
1515a89e 732 }
264867fd 733
9f85bed4 734 /// Format the message as a small table
1515a89e 735
b5de723d 736 $output->text = strip_tags($outinfo.': '.$outmain);
7d792369 737
5379d249 738 $output->html = "<table class=\"chat-message\"><tr$rowclass><td class=\"picture\" valign=\"top\">$message->picture</td><td class=\"text\">";
aa5c32fd 739 $output->html .= "<span class=\"title\">$outinfo</span>";
7d792369 740 if ($outmain) {
741 $output->html .= ": $outmain";
6e5f40ea 742 $output->basic = '<dl><dt class="title">'.$outinfo.':</dt><dd class="text">'.$outmain.'</dd></dl>';
6ee78cee 743 } else {
6e5f40ea 744 $output->basic = '<dl><dt class="title">'.$outinfo.'</dt></dl>';
7d792369 745 }
aa5c32fd 746 $output->html .= "</td></tr></table>";
7d792369 747 return $output;
b5de723d 748}
749
aa5c32fd 750function chat_format_message($message, $courseid, $currentuser, $chat_lastrow=NULL) {
b5de723d 751/// Given a message object full of information, this function
752/// formats it appropriately into text and html, then
753/// returns the formatted data.
d3bf6f92 754 global $DB;
b5de723d 755
78c98892 756 static $users; // Cache user lookups
757
758 if (isset($users[$message->userid])) {
759 $user = $users[$message->userid];
d3bf6f92 760 } else if ($user = $DB->get_record('user', array('id'=>$message->userid), 'id,picture,firstname,lastname')) {
78c98892 761 $users[$message->userid] = $user;
762 } else {
763 return NULL;
b5de723d 764 }
aa5c32fd 765 return chat_format_message_manually($message, $courseid, $user, $currentuser, $chat_lastrow);
1515a89e 766}
767
f3221af9 768function chat_get_view_actions() {
769 return array('view','view all','report');
770}
771
772function chat_get_post_actions() {
773 return array('talk');
774}
775
9ca0187e 776function chat_print_overview($courses, &$htmlarray) {
777 global $USER, $CFG;
778
779 if (empty($courses) || !is_array($courses) || count($courses) == 0) {
780 return array();
781 }
782
783 if (!$chats = get_all_instances_in_courses('chat',$courses)) {
784 return;
785 }
786
787 $strchat = get_string('modulename', 'chat');
788 $strnextsession = get_string('nextsession', 'chat');
9ca0187e 789
790 foreach ($chats as $chat) {
9ca0187e 791 if ($chat->chattime and $chat->schedule) { // A chat is scheduled
a2a37336 792 $str = '<div class="chat overview"><div class="name">'.
793 $strchat.': <a '.($chat->visible?'':' class="dimmed"').
794 ' href="'.$CFG->wwwroot.'/mod/chat/view.php?id='.$chat->coursemodule.'">'.
795 $chat->name.'</a></div>';
796 $str .= '<div class="info">'.$strnextsession.': '.userdate($chat->chattime).'</div></div>';
797
798 if (empty($htmlarray[$chat->course]['chat'])) {
799 $htmlarray[$chat->course]['chat'] = $str;
800 } else {
801 $htmlarray[$chat->course]['chat'] .= $str;
802 }
9ca0187e 803 }
9ca0187e 804 }
805}
806
0b5a80a1 807
808/**
809 * Implementation of the function for printing the form elements that control
810 * whether the course reset functionality affects the chat.
811 * @param $mform form passed by reference
812 */
813function chat_reset_course_form_definition(&$mform) {
814 $mform->addElement('header', 'chatheader', get_string('modulenameplural', 'chat'));
815 $mform->addElement('advcheckbox', 'reset_chat', get_string('removemessages','chat'));
816}
817
818/**
819 * Course reset form defaults.
820 */
821function chat_reset_course_form_defaults($course) {
822 return array('reset_chat'=>1);
823}
824
825/**
826 * Actual implementation of the rest coures functionality, delete all the
827 * chat messages for course $data->courseid.
828 * @param $data the data submitted from the reset course.
829 * @return array status array
830 */
831function chat_reset_userdata($data) {
d3bf6f92 832 global $CFG, $DB;
0b5a80a1 833
834 $componentstr = get_string('modulenameplural', 'chat');
835 $status = array();
836
837 if (!empty($data->reset_chat)) {
838 $chatessql = "SELECT ch.id
d3bf6f92 839 FROM {chat} ch
840 WHERE ch.course=?";
841 $params = array($data->courseid);
0b5a80a1 842
d3bf6f92 843 $DB->delete_records_select('chat_messages', "chatid IN ($chatessql)", $params);
6e5f40ea 844 $DB->delete_records_select('chat_messages_current', "chatid IN ($chatessql)", $params);
d3bf6f92 845 $DB->delete_records_select('chat_users', "chatid IN ($chatessql)", $params);
0b5a80a1 846 $status[] = array('component'=>$componentstr, 'item'=>get_string('removemessages', 'chat'), 'error'=>false);
847 }
848
849 /// updating dates - shift may be negative too
850 if ($data->timeshift) {
851 shift_course_mod_dates('chat', array('chattime'), $data->timeshift, $data->courseid);
852 $status[] = array('component'=>$componentstr, 'item'=>get_string('datechanged'), 'error'=>false);
853 }
854
855 return $status;
856}
857
f432bebf 858/**
859 * Returns all other caps used in module
860 */
861function chat_get_extra_capabilities() {
862 return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames');
863}
864
47cfd331 865require_once($CFG->libdir . '/portfoliolib.php');
866class chat_portfolio_caller extends portfolio_module_caller_base {
867
868 private $chat;
0d06b6fd 869 protected $start;
870 protected $end;
871
872 public static function expected_callbackargs() {
873 return array(
874 'id' => true,
875 'start' => false,
876 'end' => false,
877 );
878 }
879
880 public function load_data() {
881 global $DB;
47cfd331 882
0d06b6fd 883 if (!$this->cm = get_coursemodule_from_id('chat', $this->id)) {
34035201 884 throw new portfolio_caller_exception('invalidid', 'chat');
47cfd331 885 }
886 $this->chat = $DB->get_record('chat', array('id' => $this->cm->instance));
887 $select = 'chatid = ?';
888 $params = array($this->chat->id);
0d06b6fd 889 if ($this->start && $this->end) {
47cfd331 890 $select .= ' AND timestamp >= ? AND timestamp <= ?';
0d06b6fd 891 $params[] = $this->start;
892 $params[] = $this->end;
47cfd331 893 }
894 $this->messages = $DB->get_records_select(
895 'chat_messages',
896 $select,
897 $params,
898 'timestamp ASC'
899 );
900 $select .= ' AND userid = ?';
0d06b6fd 901 $params[] = $this->user->id;
47cfd331 902 $this->participated = $DB->record_exists_select(
903 'chat_messages',
904 $select,
905 $params
906 );
0d06b6fd 907 }
908
a7d90683 909 public static function supported_formats() {
6be1dcae 910 return array(PORTFOLIO_FORMAT_PLAINHTML);
47cfd331 911 }
912
913 public function expected_time() {
d8606b20 914 return portfolio_expected_time_db(count($this->messages));
47cfd331 915 }
916
917 public function get_sha1() {
918 $str = '';
919 ksort($this->messages);
920 foreach ($this->messages as $m) {
921 $str .= implode('', (array)$m);
922 }
923 return sha1($str);
924 }
925
926 public function check_permissions() {
927 $context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
928 return has_capability('mod/chat:exportsession', $context)
929 || ($this->participated
930 && has_capability('mod/chat:exportparticipatedsession', $context));
931 }
932
933 public function prepare_package() {
934 $content = '';
5a04379a 935 $lasttime = 0;
936 $sessiongap = 5 * 60; // 5 minutes silence means a new session
47cfd331 937 foreach ($this->messages as $message) { // We are walking FORWARDS through messages
5a04379a 938 $m = clone $message; // grrrrrr - this causes the sha1 to change as chat_format_message changes what it's passed.
47cfd331 939 $formatmessage = chat_format_message($m, null, $this->user);
940 if (!isset($formatmessage->html)) {
941 continue;
942 }
5a04379a 943 if (empty($lasttime) || (($message->timestamp - $lasttime) > $sessiongap)) {
944 $content .= '<hr />';
945 $content .= userdate($message->timestamp);
946 }
47cfd331 947 $content .= $formatmessage->html;
5a04379a 948 $lasttime = $message->timestamp;
47cfd331 949 }
950 $content = preg_replace('/\<img[^>]*\>/', '', $content);
951
6be1dcae 952 $this->exporter->write_new_file($content, clean_filename($this->cm->name . '-session.html'), false);
47cfd331 953 }
954
955 public static function display_name() {
956 return get_string('modulename', 'chat');
957 }
958
959 public function get_return_url() {
960 global $CFG;
961
962 return $CFG->wwwroot . '/mod/chat/report.php?id='
963 . $this->cm->id . ((isset($this->start))
964 ? '&start=' . $this->start . '&end=' . $this->end
965 : '');
966 }
967}
968
1515a89e 969?>