MDL-18910 moving modedit features to modname_supports()
[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');
214b1cf7 5require_once($CFG->libdir.'/portfoliolib.php');
c4d588cc 6
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) {
19f5b2db 156 if(!blocks_delete_all_on_page($pagetype, $chat->id)) {
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
547ac664 449 return $DB->get_records_sql("SELECT
450 DISTINCT u.id, u.firstname, u.lastname, u.picture, c.lastmessageping, c.firstping, u.imagealt
451 FROM {chat_users} c JOIN {user} u ON u.id = c.userid $groupingjoin
452 WHERE c.chatid = :chatid $groupselect
453 ORDER BY c.firstping ASC", $params);
1515a89e 454}
455
84a2fdd7 456function chat_get_latest_message($chatid, $groupid=0) {
f33e1ed4 457 global $DB;
1515a89e 458
d3bf6f92 459 $params = array('chatid'=>$chatid, 'groupid'=>$groupid);
1515a89e 460
84a2fdd7 461 if ($groupid) {
d3bf6f92 462 $groupselect = "AND (groupid=:groupid OR groupid=0)";
84a2fdd7 463 } else {
464 $groupselect = "";
465 }
466
547ac664 467 $sql = "SELECT *
468 FROM {chat_messages_current} WHERE chatid = :chatid $groupselect
469 ORDER BY timestamp DESC";
03cedd62 470
547ac664 471 // return the lastest one message
f33e1ed4 472 return $DB->get_record_sql($sql, $params, true);
1515a89e 473}
474
5a8625e4 475
1515a89e 476//////////////////////////////////////////////////////////////////////
516121bd 477// login if not already logged in
1515a89e 478
a32c7772 479function chat_login_user($chatid, $version, $groupid, $course) {
d3bf6f92 480 global $USER, $DB;
481
482 if (($version != 'sockets') and $chatuser = $DB->get_record('chat_users', array('chatid'=>$chatid, 'userid'=>$USER->id, 'groupid'=>$groupid))) {
7f0483f6 483 // this will update logged user information
516121bd 484 $chatuser->version = $version;
d96466d2 485 $chatuser->ip = $USER->lastip;
516121bd 486 $chatuser->lastping = time();
487 $chatuser->lang = current_language();
1515a89e 488
d96466d2 489 // Sometimes $USER->lastip is not setup properly
d13ef2fb 490 // during login. Update with current value if possible
f83edcb1 491 // or provide a dummy value for the db
d13ef2fb 492 if (empty($chatuser->ip)) {
493 $chatuser->ip = getremoteaddr();
494 if (empty($chatuser->ip)) {
f83edcb1 495 $chatuser->ip = '';
d13ef2fb 496 }
497 }
498
7f0483f6 499 if (($chatuser->course != $course->id) or ($chatuser->userid != $USER->id)) {
516121bd 500 return false;
501 }
d3bf6f92 502 if (!$DB->update_record('chat_users', $chatuser)) {
516121bd 503 return false;
504 }
516121bd 505 } else {
6ee78cee 506 $chatuser = new object();
516121bd 507 $chatuser->chatid = $chatid;
508 $chatuser->userid = $USER->id;
509 $chatuser->groupid = $groupid;
510 $chatuser->version = $version;
d96466d2 511 $chatuser->ip = $USER->lastip;
516121bd 512 $chatuser->lastping = $chatuser->firstping = $chatuser->lastmessageping = time();
513 $chatuser->sid = random_string(32);
3dfd307f 514 $chatuser->course = $course->id; //caching - needed for current_language too
515 $chatuser->lang = current_language(); //caching - to resource intensive to find out later
516121bd 516
d96466d2 517 // Sometimes $USER->lastip is not setup properly
274f0091 518 // during login. Update with current value if possible
519 // or provide a dummy value for the db
520 if (empty($chatuser->ip)) {
521 $chatuser->ip = getremoteaddr();
522 if (empty($chatuser->ip)) {
523 $chatuser->ip = '';
524 }
525 }
526
527
d3bf6f92 528 if (!$DB->insert_record('chat_users', $chatuser)) {
516121bd 529 return false;
530 }
531
a32c7772 532 if ($version == 'sockets') {
533 // do not send 'enter' message, chatd will do it
534 } else {
6ee78cee 535 $message = new object();
2ac0d13b 536 $message->chatid = $chatuser->chatid;
537 $message->userid = $chatuser->userid;
538 $message->groupid = $groupid;
539 $message->message = 'enter';
540 $message->system = 1;
541 $message->timestamp = time();
542
7f0483f6 543 if (!$DB->insert_record('chat_messages', $message) || !$DB->insert_record('chat_messages_current', $message))
544 {
2f52a088 545 print_error('cantinsert', 'chat');
2ac0d13b 546 }
516121bd 547 }
1515a89e 548 }
549
550 return $chatuser->sid;
551}
552
7d792369 553function chat_delete_old_users() {
554// Delete the old and in the way
d3bf6f92 555 global $CFG, $DB;
b5012f3e 556
e7fbd0b3 557 $timeold = time() - $CFG->chat_old_ping;
953eb6f3 558 $timeoldext = time() - ($CFG->chat_old_ping*10); // JSless gui_basic needs much longer timeouts
a32c7772 559
d3bf6f92 560 $query = "(version<>'basic' AND lastping<?) OR (version='basic' AND lastping<?)";
561 $params = array($timeold, $timeoldext);
7d792369 562
d3bf6f92 563 if ($oldusers = $DB->get_records_select('chat_users', $query, $params) ) {
564 $DB->delete_records_select('chat_users', $query, $params);
7d792369 565 foreach ($oldusers as $olduser) {
6ee78cee 566 $message = new object();
516121bd 567 $message->chatid = $olduser->chatid;
568 $message->userid = $olduser->userid;
569 $message->groupid = $olduser->groupid;
570 $message->message = 'exit';
571 $message->system = 1;
7d792369 572 $message->timestamp = time();
b5de723d 573
547ac664 574 if (!$DB->insert_record('chat_messages', $message)
575 || !$DB->insert_record('chat_messages_current', $message) )
576 {
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 }
7f0483f6 727 } elseif (substr($text, 0, 2) == 'To') {
728 $pattern = '#To[[:space:]](.*):(.*)#';
729 preg_match($pattern, trim($text), $matches);
730 $special = true;
731 $outinfo = $message->strtime;
732 $outmain = $sender->firstname.' '.get_string('saidto', 'chat').' <i>'.$matches[1].'</i>: '.$matches[2];
927a7808 733 }
9f85bed4 734
927a7808 735 if(!$special) {
b5de723d 736 $outinfo = $message->strtime.' '.$sender->firstname;
7d792369 737 $outmain = $text;
1515a89e 738 }
264867fd 739
9f85bed4 740 /// Format the message as a small table
1515a89e 741
b5de723d 742 $output->text = strip_tags($outinfo.': '.$outmain);
7d792369 743
5379d249 744 $output->html = "<table class=\"chat-message\"><tr$rowclass><td class=\"picture\" valign=\"top\">$message->picture</td><td class=\"text\">";
aa5c32fd 745 $output->html .= "<span class=\"title\">$outinfo</span>";
7d792369 746 if ($outmain) {
747 $output->html .= ": $outmain";
6e5f40ea 748 $output->basic = '<dl><dt class="title">'.$outinfo.':</dt><dd class="text">'.$outmain.'</dd></dl>';
6ee78cee 749 } else {
6e5f40ea 750 $output->basic = '<dl><dt class="title">'.$outinfo.'</dt></dl>';
7d792369 751 }
aa5c32fd 752 $output->html .= "</td></tr></table>";
7d792369 753 return $output;
b5de723d 754}
755
aa5c32fd 756function chat_format_message($message, $courseid, $currentuser, $chat_lastrow=NULL) {
b5de723d 757/// Given a message object full of information, this function
758/// formats it appropriately into text and html, then
759/// returns the formatted data.
d3bf6f92 760 global $DB;
b5de723d 761
78c98892 762 static $users; // Cache user lookups
763
764 if (isset($users[$message->userid])) {
765 $user = $users[$message->userid];
d3bf6f92 766 } else if ($user = $DB->get_record('user', array('id'=>$message->userid), 'id,picture,firstname,lastname')) {
78c98892 767 $users[$message->userid] = $user;
768 } else {
769 return NULL;
b5de723d 770 }
aa5c32fd 771 return chat_format_message_manually($message, $courseid, $user, $currentuser, $chat_lastrow);
1515a89e 772}
773
f3221af9 774function chat_get_view_actions() {
775 return array('view','view all','report');
776}
777
778function chat_get_post_actions() {
779 return array('talk');
780}
781
9ca0187e 782function chat_print_overview($courses, &$htmlarray) {
783 global $USER, $CFG;
784
785 if (empty($courses) || !is_array($courses) || count($courses) == 0) {
786 return array();
787 }
788
789 if (!$chats = get_all_instances_in_courses('chat',$courses)) {
790 return;
791 }
792
793 $strchat = get_string('modulename', 'chat');
794 $strnextsession = get_string('nextsession', 'chat');
9ca0187e 795
796 foreach ($chats as $chat) {
9ca0187e 797 if ($chat->chattime and $chat->schedule) { // A chat is scheduled
a2a37336 798 $str = '<div class="chat overview"><div class="name">'.
799 $strchat.': <a '.($chat->visible?'':' class="dimmed"').
800 ' href="'.$CFG->wwwroot.'/mod/chat/view.php?id='.$chat->coursemodule.'">'.
801 $chat->name.'</a></div>';
802 $str .= '<div class="info">'.$strnextsession.': '.userdate($chat->chattime).'</div></div>';
803
804 if (empty($htmlarray[$chat->course]['chat'])) {
805 $htmlarray[$chat->course]['chat'] = $str;
806 } else {
807 $htmlarray[$chat->course]['chat'] .= $str;
808 }
9ca0187e 809 }
9ca0187e 810 }
811}
812
0b5a80a1 813
814/**
815 * Implementation of the function for printing the form elements that control
816 * whether the course reset functionality affects the chat.
817 * @param $mform form passed by reference
818 */
819function chat_reset_course_form_definition(&$mform) {
820 $mform->addElement('header', 'chatheader', get_string('modulenameplural', 'chat'));
821 $mform->addElement('advcheckbox', 'reset_chat', get_string('removemessages','chat'));
822}
823
824/**
825 * Course reset form defaults.
826 */
827function chat_reset_course_form_defaults($course) {
828 return array('reset_chat'=>1);
829}
830
831/**
832 * Actual implementation of the rest coures functionality, delete all the
833 * chat messages for course $data->courseid.
834 * @param $data the data submitted from the reset course.
835 * @return array status array
836 */
837function chat_reset_userdata($data) {
d3bf6f92 838 global $CFG, $DB;
0b5a80a1 839
840 $componentstr = get_string('modulenameplural', 'chat');
841 $status = array();
842
843 if (!empty($data->reset_chat)) {
844 $chatessql = "SELECT ch.id
d3bf6f92 845 FROM {chat} ch
846 WHERE ch.course=?";
847 $params = array($data->courseid);
0b5a80a1 848
d3bf6f92 849 $DB->delete_records_select('chat_messages', "chatid IN ($chatessql)", $params);
6e5f40ea 850 $DB->delete_records_select('chat_messages_current', "chatid IN ($chatessql)", $params);
d3bf6f92 851 $DB->delete_records_select('chat_users', "chatid IN ($chatessql)", $params);
0b5a80a1 852 $status[] = array('component'=>$componentstr, 'item'=>get_string('removemessages', 'chat'), 'error'=>false);
853 }
854
855 /// updating dates - shift may be negative too
856 if ($data->timeshift) {
857 shift_course_mod_dates('chat', array('chattime'), $data->timeshift, $data->courseid);
858 $status[] = array('component'=>$componentstr, 'item'=>get_string('datechanged'), 'error'=>false);
859 }
860
861 return $status;
862}
863
f432bebf 864/**
865 * Returns all other caps used in module
866 */
867function chat_get_extra_capabilities() {
868 return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames');
869}
870
47cfd331 871class chat_portfolio_caller extends portfolio_module_caller_base {
872
873 private $chat;
0d06b6fd 874 protected $start;
875 protected $end;
876
877 public static function expected_callbackargs() {
878 return array(
879 'id' => true,
880 'start' => false,
881 'end' => false,
882 );
883 }
884
885 public function load_data() {
886 global $DB;
47cfd331 887
0d06b6fd 888 if (!$this->cm = get_coursemodule_from_id('chat', $this->id)) {
34035201 889 throw new portfolio_caller_exception('invalidid', 'chat');
47cfd331 890 }
891 $this->chat = $DB->get_record('chat', array('id' => $this->cm->instance));
892 $select = 'chatid = ?';
893 $params = array($this->chat->id);
0d06b6fd 894 if ($this->start && $this->end) {
47cfd331 895 $select .= ' AND timestamp >= ? AND timestamp <= ?';
0d06b6fd 896 $params[] = $this->start;
897 $params[] = $this->end;
47cfd331 898 }
899 $this->messages = $DB->get_records_select(
900 'chat_messages',
901 $select,
902 $params,
903 'timestamp ASC'
904 );
905 $select .= ' AND userid = ?';
0d06b6fd 906 $params[] = $this->user->id;
47cfd331 907 $this->participated = $DB->record_exists_select(
908 'chat_messages',
909 $select,
910 $params
911 );
0d06b6fd 912 }
913
a7d90683 914 public static function supported_formats() {
6be1dcae 915 return array(PORTFOLIO_FORMAT_PLAINHTML);
47cfd331 916 }
917
918 public function expected_time() {
d8606b20 919 return portfolio_expected_time_db(count($this->messages));
47cfd331 920 }
921
922 public function get_sha1() {
923 $str = '';
924 ksort($this->messages);
925 foreach ($this->messages as $m) {
926 $str .= implode('', (array)$m);
927 }
928 return sha1($str);
929 }
930
931 public function check_permissions() {
932 $context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
933 return has_capability('mod/chat:exportsession', $context)
934 || ($this->participated
935 && has_capability('mod/chat:exportparticipatedsession', $context));
936 }
937
938 public function prepare_package() {
939 $content = '';
5a04379a 940 $lasttime = 0;
941 $sessiongap = 5 * 60; // 5 minutes silence means a new session
47cfd331 942 foreach ($this->messages as $message) { // We are walking FORWARDS through messages
5a04379a 943 $m = clone $message; // grrrrrr - this causes the sha1 to change as chat_format_message changes what it's passed.
47cfd331 944 $formatmessage = chat_format_message($m, null, $this->user);
945 if (!isset($formatmessage->html)) {
946 continue;
947 }
5a04379a 948 if (empty($lasttime) || (($message->timestamp - $lasttime) > $sessiongap)) {
949 $content .= '<hr />';
950 $content .= userdate($message->timestamp);
951 }
47cfd331 952 $content .= $formatmessage->html;
5a04379a 953 $lasttime = $message->timestamp;
47cfd331 954 }
955 $content = preg_replace('/\<img[^>]*\>/', '', $content);
956
6be1dcae 957 $this->exporter->write_new_file($content, clean_filename($this->cm->name . '-session.html'), false);
47cfd331 958 }
959
960 public static function display_name() {
961 return get_string('modulename', 'chat');
962 }
963
964 public function get_return_url() {
965 global $CFG;
966
967 return $CFG->wwwroot . '/mod/chat/report.php?id='
968 . $this->cm->id . ((isset($this->start))
969 ? '&start=' . $this->start . '&end=' . $this->end
970 : '');
971 }
972}
973
42f103be 974/**
975 * @param string $feature FEATURE_xx constant for requested feature
976 * @return mixed True if module supports feature, null if doesn't know
977 */
978function chat_supports($feature) {
979 switch($feature) {
980 case FEATURE_GROUPS: return true;
981 case FEATURE_GROUPINGS: return true;
982 case FEATURE_GROUPMEMBERSONLY: return true;
983 case FEATURE_MODEDIT_INTRO_EDITOR: return true;
984 case FEATURE_COMPLETION_TRACKS_VIEWS: return false;
985 case FEATURE_GRADE_HAS_GRADE: return false;
986 case FEATURE_GRADE_OUTCOMES: return true;
987
988 default: return null;
989 }
990}
991