3 * Global Search Engine for Moodle
7 * @subpackage document_wrappers
8 * @author Valery Fremaux [valery.fremaux@club-internet.fr] > 1.8
9 * @contributor Tatsuva Shirai 20090530
11 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
13 * document handling for chat activity module
14 * This file contains the mapping between a chat history and it's indexable counterpart,
16 * Functions for iterating and retrieving the necessary records are now also included
17 * in this file, rather than mod/chat/lib.php
22 * includes and requires
24 require_once("$CFG->dirroot/search/documents/document.php");
25 require_once("$CFG->dirroot/mod/chat/lib.php");
28 * a class for representing searchable information
31 class ChatTrackSearchDocument
extends SearchDocument
{
36 public function __construct(&$chatsession, $chat_id, $chat_module_id, $course_id, $group_id, $context_id) {
37 // generic information; required
38 $doc->docid
= $chat_id.'-'.$chatsession['sessionstart'].'-'.$chatsession['sessionend'];
39 $doc->documenttype
= SEARCH_TYPE_CHAT
;
40 $doc->itemtype
= 'session';
41 $doc->contextid
= $context_id;
43 $duration = $chatsession['sessionend'] - $chatsession['sessionstart'];
44 // we cannot call userdate with relevant locale at indexing time.
45 $doc->title
= get_string('chatreport', 'chat').' '.get_string('openedon', 'search').' TT_'.$chatsession['sessionstart'].'_TT ('.get_string('duration', 'search').' : '.get_string('numseconds', '', $duration).')';
46 $doc->date
= $chatsession['sessionend'];
48 //remove '(ip.ip.ip.ip)' from chat author list
49 $doc->author
= preg_replace('/\(.*?\)/', '', $chatsession['authors']);
50 $doc->contents
= $chatsession['content'];
51 $doc->url
= chat_make_link($chat_module_id, $chatsession['sessionstart'], $chatsession['sessionend']);
53 // module specific information; optional
54 $data->chat
= $chat_id;
56 // construct the parent class
57 parent
::__construct($doc, $data, $course_id, $group_id, 0, 'mod/'.SEARCH_TYPE_CHAT
);
63 * constructs a valid link to a chat content
64 * @param cm_id the chat course module
65 * @param start the start time of the session
66 * @param end th end time of the session
68 * @return a well formed link to session display
70 function chat_make_link($cm_id, $start, $end) {
73 return $CFG->wwwroot
.'/mod/chat/report.php?id='.$cm_id.'&start='.$start.'&end='.$end;
77 * fetches all the records for a given session and assemble them as a unique track
78 * we revamped here the code of report.php for making sessions, but without any output.
79 * note that we should collect sessions "by groups" if groupmode() is SEPARATEGROUPS.
80 * @param int $chat_id the database
81 * @param int $fromtime
84 * @return an array of objects representing the chat sessions.
86 function chat_get_session_tracks($chat_id, $fromtime = 0, $totime = 0) {
89 $chat = get_record('chat', 'id', $chat_id);
90 $course = get_record('course', 'id', $chat->course
);
91 $coursemodule = get_field('modules', 'id', 'name', 'data');
92 $cm = get_record('course_modules', 'course', $course->id
, 'module', $coursemodule, 'instance', $chat->id
);
93 if (empty($cm)) { // Shirai 20090530
94 mtrace("Missing this chat: Course=".$chat->course
."/ ChatID=".$chat_id);
97 $groupmode = groupmode($course, $cm);
99 $fromtimeclause = ($fromtime) ?
"AND timestamp >= {$fromtime}" : '';
100 $totimeclause = ($totime) ?
"AND timestamp <= {$totime}" : '';
102 $messages = get_records_select('chat_messages', "chatid = '{$chat_id}' $fromtimeclause $totimeclause", "timestamp DESC");
104 // splits discussions against groups
105 $groupedMessages = array();
106 if ($groupmode != SEPARATEGROUPS
){
107 foreach($messages as $aMessage){
108 $groupedMessages[$aMessage->groupid
][] = $aMessage;
111 $groupedMessages[-1] = &$messages;
113 $sessiongap = 5 * 60; // 5 minutes silence means a new session
116 $sessionusers = array();
119 foreach ($groupedMessages as $groupId => $messages) { // We are walking BACKWARDS through the messages
120 $messagesleft = count($messages);
121 foreach ($messages as $message) { // We are walking BACKWARDS through the messages
122 $messagesleft --; // Countdown
124 if ($message->system
) {
127 // we are within a session track
128 if ((($lasttime - $message->timestamp
) < $sessiongap) and $messagesleft) { // Same session
129 if (count($tracks) > 0){
130 if ($message->userid
) { // Remember user and count messages
131 $tracks[count($tracks) - 1]->sessionusers
[$message->userid
] = $message->userid
;
132 // update last track (if exists) record appending content (remember : we go backwards)
134 $tracks[count($tracks) - 1]->content
.= ' '.$message->message
;
135 $tracks[count($tracks) - 1]->sessionstart
= $message->timestamp
;
138 // we initiate a new session track (backwards)
139 $track = new Object();
140 $track->sessionend
= $message->timestamp
;
141 $track->sessionstart
= $message->timestamp
;
142 $track->content
= $message->message
;
143 // reset the accumulator of users
144 $track->sessionusers
= array();
145 $track->sessionusers
[$message->userid
] = $message->userid
;
146 $track->groupid
= $groupId;
149 $lasttime = $message->timestamp
;
157 * part of search engine API
160 function chat_iterator() {
161 $chatrooms = get_records('chat');
166 * part of search engine API
169 function chat_get_content_for_index(&$chat) {
170 $documents = array();
171 $course = get_record('course', 'id', $chat->course
);
172 $coursemodule = get_field('modules', 'id', 'name', 'chat');
173 $cm = get_record('course_modules', 'course', $chat->course
, 'module', $coursemodule, 'instance', $chat->id
);
175 $context = get_context_instance(CONTEXT_MODULE
, $cm->id
);
177 // getting records for indexing
178 $sessionTracks = chat_get_session_tracks($chat->id
);
180 foreach($sessionTracks as $aTrackId => $aTrack) {
181 foreach($aTrack->sessionusers
as $aUserId){
182 $user = get_record('user', 'id', $aUserId);
183 $aTrack->authors
= ($user) ?
fullname($user) : '' ;
184 $documents[] = new ChatTrackSearchDocument(get_object_vars($aTrack), $chat->id
, $cm->id
, $chat->course
, $aTrack->groupid
, $context->id
);
194 * returns a single data search document based on a chat_session id
195 * chat session id is a text composite identifier made of :
197 * - the timestamp when the session starts
198 * - the timestamp when the session ends
199 * @param id the multipart chat session id
200 * @param itemtype the type of information (session is the only type)
202 function chat_single_document($id, $itemtype) {
203 list($chat_id, $sessionstart, $sessionend) = split('-', $id);
204 $chat = get_record('chat', 'id', $chat_id);
205 $course = get_record('course', 'id', $chat->course
);
206 $coursemodule = get_field('modules', 'id', 'name', 'chat');
207 $cm = get_record('course_modules', 'course', $course->id
, 'module', $coursemodule, 'instance', $chat->id
);
209 $context = get_context_instance(CONTEXT_MODULE
, $cm->id
);
211 // should be only one
212 $tracks = chat_get_session_tracks($chat->id
, $sessionstart, $sessionstart);
214 $aTrack = $tracks[0];
215 $document = new ChatTrackSearchDocument(get_object_vars($aTrack), $chat_id, $cm->id
, $chat->course
, $aTrack->groupid
, $context->id
);
223 * dummy delete function that packs id with itemtype.
224 * this was here for a reason, but I can't remember it at the moment.
227 function chat_delete($info, $itemtype) {
229 $object->itemtype
= $itemtype;
234 * returns the var names needed to build a sql query for addition/deletions
235 * // TODO chat indexable records are virtual. Should proceed in a special way
237 function chat_db_names() {
238 //[primary id], [table name], [time created field name], [time modified field name]
243 * this function handles the access policy to contents indexed as searchable documents. If this
244 * function does not exist, the search engine assumes access is allowed.
245 * When this point is reached, we already know that :
246 * - user is legitimate in the surrounding context
247 * - user may be guest and guest access is allowed to the module
248 * - the function may perform local checks within the module information logic
249 * @param path the access path to the module script code
250 * @param itemtype the information subclassing (usefull for complex modules, defaults to 'standard')
251 * @param this_id the item id within the information class denoted by entry_type. In chats, this id
252 * points out a session history which is a close sequence of messages.
253 * @param user the user record denoting the user who searches
254 * @param group_id the current group used by the user when searching
256 * @return true if access is allowed, false elsewhere
258 function chat_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
261 include_once("{$CFG->dirroot}/{$path}/lib.php");
263 list($chat_id, $sessionstart, $sessionend) = split('-', $this_id);
264 // get the chat session and all related stuff
265 $chat = get_record('chat', 'id', $chat_id);
266 $context = get_record('context', 'id', $context_id);
267 $cm = get_record('course_modules', 'id', $context->instanceid
);
268 if (empty($cm)) return false; // Shirai 20090530 - MDL19342 - course module might have been delete
270 if (!$cm->visible
and !has_capability('moodle/course:viewhiddenactivities', $context)){
271 if (!empty($CFG->search_access_debug
)) echo "search reject : hidden chat ";
275 //group consistency check : checks the following situations about groups
276 // trap if user is not same group and groups are separated
277 $course = get_record('course', 'id', $chat->course
);
278 if ((groupmode($course, $cm) == SEPARATEGROUPS
) && !ismember($group_id) && !has_capability('moodle/site:accessallgroups', $context)){
279 if (!empty($CFG->search_access_debug
)) echo "search reject : chat element is in separated group ";
283 //ownership check : checks the following situations about user
284 // trap if user is not owner and has cannot see other's entries
285 // TODO : typically may be stored into indexing cache
286 if (!has_capability('mod/chat:readlog', $context)){
287 if (!empty($CFG->search_access_debug
)) echo "search reject : cannot read past sessions ";
295 * this call back is called when displaying the link for some last post processing
298 function chat_link_post_processing($title){
300 setLocale(LC_TIME
, substr(current_language(), 0, 2));
301 $title = preg_replace('/TT_(.*)_TT/e', "userdate(\\1)", $title);
303 if ($CFG->block_search_utf8dir
){
304 return mb_convert_encoding($title, 'UTF-8', 'auto');
306 return mb_convert_encoding($title, 'auto', 'UTF-8');