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