3 * Global Search Engine for Moodle
4 * add-on 1.8+ : Valery Fremaux [valery.fremaux@club-internet.fr]
7 * document handling for chat activity module
8 * This file contains the mapping between a chat history and it's indexable counterpart,
10 * Functions for iterating and retrieving the necessary records are now also included
11 * in this file, rather than mod/chat/lib.php
14 require_once("$CFG->dirroot/search/documents/document.php");
15 require_once("$CFG->dirroot/mod/chat/lib.php");
18 * a class for representing searchable information
21 class ChatTrackSearchDocument
extends SearchDocument
{
27 public function __construct(&$chatsession, $chat_module_id, $course_id, $group_id, $context_id) {
28 // generic information; required
29 $doc->docid
= $chat_module_id.'-'.$chatsession['sessionstart'].'-'.$chatsession['sessionend'];
30 $doc->documenttype
= SEARCH_TYPE_CHAT
;
31 $doc->itemtype
= 'session';
32 $doc->contextid
= $context_id;
34 $duration = $chatsession['sessionend'] - $chatsession['sessionstart'];
35 // we cannot call userdate with relevant locale at indexing time.
36 $doc->title
= get_string('chatreport', 'chat').' '.get_string('openedon', 'search').' TT_'.$chatsession['sessionstart'].'_TT ('.get_string('duration', 'search').' : '.get_string('numseconds', '', $duration).')';
37 $doc->date
= $chatsession['sessionend'];
39 //remove '(ip.ip.ip.ip)' from chat author list
40 $doc->author
= preg_replace('/\(.*?\)/', '', $chatsession['authors']);
41 $doc->contents
= $chatsession['content'];
42 $doc->url
= chat_make_link($chat_module_id, $chatsession['sessionstart'], $chatsession['sessionend']);
44 // module specific information; optional
45 $data->chat
= $chat_module_id;
47 // construct the parent class
48 parent
::__construct($doc, $data, $course_id, $group_id, 0, PATH_FOR_SEARCH_TYPE_CHAT
);
50 } //ChatTrackSearchDocument
54 * constructs a valid link to a chat content
55 * @param cm_id the chat course module
56 * @param start the start time of the session
57 * @param end th end time of the session
58 * @return a well formed link to session display
60 function chat_make_link($cm_id, $start, $end) {
63 return $CFG->wwwroot
.'/mod/chat/report.php?id='.$cm_id.'&start='.$start.'&end='.$end;
67 * fetches all the records for a given session and assemble them as a unique track
68 * we revamped here the code of report.php for making sessions, but without any output.
69 * note that we should collect sessions "by groups" if groupmode() is SEPARATEGROUPS.
70 * @param chat_id the database
71 * @return an array of objects representing the chat sessions.
73 function chat_get_session_tracks($chat_id, $fromtime = 0, $totime = 0) {
76 $chat = get_record('chat', 'id', $chat_id);
77 $course = get_record('course', 'id', $chat->course
);
78 $coursemodule = get_field('modules', 'id', 'name', 'data');
79 $cm = get_record('course_modules', 'course', $course->id
, 'module', $coursemodule, 'instance', $chat->id
);
80 $groupmode = groupmode($course, $cm);
82 $fromtimeclause = ($fromtime) ?
"AND timestamp >= {$fromtime}" : '';
83 $totimeclause = ($totime) ?
"AND timestamp <= {$totime}" : '';
85 $messages = get_records_select('chat_messages', "chatid = '{$chat_id}' $fromtimeclause $totimeclause", "timestamp DESC");
87 // splits discussions against groups
88 $groupedMessages = array();
89 if ($groupmode != SEPARATEGROUPS
){
90 foreach($messages as $aMessage){
91 $groupedMessages[$aMessage->groupid
][] = $aMessage;
95 $groupedMessages[-1] = &$messages;
97 $sessiongap = 5 * 60; // 5 minutes silence means a new session
100 $sessionusers = array();
103 foreach ($groupedMessages as $groupId => $messages) { // We are walking BACKWARDS through the messages
104 $messagesleft = count($messages);
105 foreach ($messages as $message) { // We are walking BACKWARDS through the messages
106 $messagesleft --; // Countdown
108 if ($message->system
) {
111 // we are within a session track
112 if ((($lasttime - $message->timestamp
) < $sessiongap) and $messagesleft) { // Same session
113 if (count($tracks) > 0){
114 if ($message->userid
) { // Remember user and count messages
115 $tracks[count($tracks) - 1]->sessionusers
[$message->userid
] = $message->userid
;
116 // update last track (if exists) record appending content (remember : we go backwards)
118 $tracks[count($tracks) - 1]->content
.= ' '.$message->message
;
119 $tracks[count($tracks) - 1]->sessionstart
= $message->timestamp
;
122 // we initiate a new session track (backwards)
124 $track = new Object();
125 $track->sessionend
= $message->timestamp
;
126 $track->sessionstart
= $message->timestamp
;
127 $track->content
= $message->message
;
128 // reset the accumulator of users
129 $track->sessionusers
= array();
130 $track->sessionusers
[$message->userid
] = $message->userid
;
131 $track->groupid
= $groupId;
134 $lasttime = $message->timestamp
;
139 } //chat_get_session_tracks
142 * part of search engine API
145 function chat_iterator() {
146 $chatrooms = get_records('chat');
151 * part of search engine API
154 function chat_get_content_for_index(&$chat) {
155 $documents = array();
156 $course = get_record('course', 'id', $chat->course
);
157 $coursemodule = get_field('modules', 'id', 'name', 'chat');
158 $cm = get_record('course_modules', 'course', $course->id
, 'module', $coursemodule, 'instance', $chat->id
);
159 $context = get_context_instance(CONTEXT_MODULE
, $cm->id
);
161 // getting records for indexing
162 $sessionTracks = chat_get_session_tracks($chat->id
);
164 foreach($sessionTracks as $aTrackId => $aTrack) {
165 foreach($aTrack->sessionusers
as $aUserId){
166 $user = get_record('user', 'id', $aUserId);
167 $aTrack->authors
= ($user) ?
$user->firstname
.' '.$user->lastname
: '' ;
168 $documents[] = new ChatTrackSearchDocument(get_object_vars($aTrack), $cm->id
, $chat->course
, $aTrack->groupid
, $context->id
);
173 } //chat_get_content_for_index
176 * returns a single data search document based on a chat_session id
177 * chat session id is a text composite identifier made of :
179 * - the timestamp when the session starts
180 * - the timestamp when the session ends
181 * @param id the multipart chat session id
182 * @param itemtype the type of information (session is the only type)
184 function chat_single_document($id, $itemtype) {
185 list($chat_id, $sessionstart, $sessionend) = split('-', $id);
186 $chat = get_record('chat', 'id', $chat_id);
187 $course = get_record('course', 'id', $chat->course
);
188 $coursemodule = get_field('modules', 'id', 'name', 'chat');
189 $cm = get_record('course_modules', 'course', $course->id
, 'module', $coursemodule, 'instance', $chat->id
);
190 $context = get_context_instance(CONTEXT_MODULE
, $cm->id
);
192 // should be only one
193 $tracks = chat_get_session_tracks($chat->id
, $sessionstart, $sessionstart);
195 $aTrack = $tracks[0];
196 $documents[] = new ChatTrackSearchDocument(get_object_vars($aTrack), $cm->id
, $chat->course
, $aTrack->groupid
, $context->id
);
198 } //chat_single_document
201 * dummy delete function that packs id with itemtype.
202 * this was here for a reason, but I can't remember it at the moment.
205 function chat_delete($info, $itemtype) {
207 $object->itemtype
= $itemtype;
212 * returns the var names needed to build a sql query for addition/deletions
213 * // TODO chat indexable records are virtual. Should proceed in a special way
215 function chat_db_names() {
216 //[primary id], [table name], [time created field name], [time modified field name]
221 * this function handles the access policy to contents indexed as searchable documents. If this
222 * function does not exist, the search engine assumes access is allowed.
223 * When this point is reached, we already know that :
224 * - user is legitimate in the surrounding context
225 * - user may be guest and guest access is allowed to the module
226 * - the function may perform local checks within the module information logic
227 * @param path the access path to the module script code
228 * @param itemtype the information subclassing (usefull for complex modules, defaults to 'standard')
229 * @param this_id the item id within the information class denoted by entry_type. In chats, this id
230 * points out a session history which is a close sequence of messages.
231 * @param user the user record denoting the user who searches
232 * @param group_id the current group used by the user when searching
233 * @return true if access is allowed, false elsewhere
235 function chat_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
238 include_once("{$CFG->dirroot}/{$path}/lib.php");
240 list($chat_id, $sessionstart, $sessionend) = split('-', $id);
242 // get the chat session and all related stuff
243 $chat = get_record('chat', 'id', $chat_id);
244 $course = get_record('course', 'id', $chat->course
);
245 $module_context = get_record('context', 'id', $context_id);
246 $cm = get_record('course_modules', 'id', $module_context->instanceid
);
247 if (!$cm->visible
and !has_capability('moodle/course:viewhiddenactivities', $module_context)) return false;
249 //group consistency check : checks the following situations about groups
250 // trap if user is not same group and groups are separated
251 $current_group = get_current_group($course->id
);
252 if ((groupmode($course) == SEPARATEGROUPS
) && !ismember($group_id) && !has_capability('moodle/site:accessallgroups', $module_context)) return false;
254 //ownership check : checks the following situations about user
255 // trap if user is not owner and has cannot see other's entries
256 // TODO : typically may be stored into indexing cache
257 if (!has_capability('mod/chat:readlog', $module_context)) return false;
260 } //chat_check_text_access
263 * this call back is called when displaying the link for some last post processing
266 function chat_link_post_processing($title){
267 setLocale(LC_TIME
, substr(current_language(), 0, 2));
268 $title = preg_replace('/TT_(.*)_TT/e', "userdate(\\1)", $title);
270 } //chat_link_post_processing