MDL-16553 Assignment, student view: whitespace fix
[moodle.git] / search / documents / chat_document.php
blobac56e36336ed6b76112dcc8a30ee42bf61220b60
1 <?php
2 /**
3 * Global Search Engine for Moodle
5 * @package search
6 * @category core
7 * @subpackage document_wrappers
8 * @author Valery Fremaux [valery.fremaux@club-internet.fr] > 1.8
9 * @contributor Tatsuva Shirai 20090530
10 * @date 2008/03/31
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
21 /**
22 * includes and requires
24 require_once("$CFG->dirroot/search/documents/document.php");
25 require_once("$CFG->dirroot/mod/chat/lib.php");
27 /**
28 * a class for representing searchable information
31 class ChatTrackSearchDocument extends SearchDocument {
33 /**
34 * constructor
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);
62 /**
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
67 * @uses CFG
68 * @return a well formed link to session display
70 function chat_make_link($cm_id, $start, $end) {
71 global $CFG;
73 return $CFG->wwwroot.'/mod/chat/report.php?id='.$cm_id.'&amp;start='.$start.'&amp;end='.$end;
76 /**
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
82 * @param int $totime
83 * @uses CFG
84 * @return an array of objects representing the chat sessions.
86 function chat_get_session_tracks($chat_id, $fromtime = 0, $totime = 0) {
87 global $CFG;
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);
95 return array();
97 $groupmode = groupmode($course, $cm);
99 $fromtimeclause = ($fromtime) ? "AND timestamp >= {$fromtime}" : '';
100 $totimeclause = ($totime) ? "AND timestamp <= {$totime}" : '';
101 $tracks = array();
102 $messages = get_records_select('chat_messages', "chatid = '{$chat_id}' $fromtimeclause $totimeclause", "timestamp DESC");
103 if ($messages){
104 // splits discussions against groups
105 $groupedMessages = array();
106 if ($groupmode != SEPARATEGROUPS){
107 foreach($messages as $aMessage){
108 $groupedMessages[$aMessage->groupid][] = $aMessage;
110 } else {
111 $groupedMessages[-1] = &$messages;
113 $sessiongap = 5 * 60; // 5 minutes silence means a new session
114 $sessionend = 0;
115 $sessionstart = 0;
116 $sessionusers = array();
117 $lasttime = time();
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) {
125 continue;
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;
137 } else {
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;
147 $tracks[] = $track;
149 $lasttime = $message->timestamp;
153 return $tracks;
157 * part of search engine API
160 function chat_iterator() {
161 $chatrooms = get_records('chat');
162 return $chatrooms;
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);
174 if ($cm){
175 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
177 // getting records for indexing
178 $sessionTracks = chat_get_session_tracks($chat->id);
179 if ($sessionTracks){
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);
188 return $documents;
190 return array();
194 * returns a single data search document based on a chat_session id
195 * chat session id is a text composite identifier made of :
196 * - the chat id
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);
208 if ($cm){
209 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
211 // should be only one
212 $tracks = chat_get_session_tracks($chat->id, $sessionstart, $sessionstart);
213 if ($tracks){
214 $aTrack = $tracks[0];
215 $document = new ChatTrackSearchDocument(get_object_vars($aTrack), $chat_id, $cm->id, $chat->course, $aTrack->groupid, $context->id);
216 return $document;
219 return null;
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) {
228 $object->id = $info;
229 $object->itemtype = $itemtype;
230 return $object;
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]
239 return null;
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
255 * @uses CFG
256 * @return true if access is allowed, false elsewhere
258 function chat_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
259 global $CFG;
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 ";
272 return false;
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 ";
280 return false;
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 ";
288 return false;
291 return true;
295 * this call back is called when displaying the link for some last post processing
298 function chat_link_post_processing($title){
299 global $CFG;
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');