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