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