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