MDL-27718 Files embedded into the course summary and section summaries are migrated...
[moodle.git] / search / documents / user_document.php
blob418193e798f0c22b1473851fa3766ee1938f613a
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 * @date 2008/03/31
10 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
11 * @version Moodle 2.0
13 * special (EXTRA) document handling for user related data
17 /**
18 * includes and requires
20 require_once($CFG->dirroot.'/search/documents/document.php');
21 require_once($CFG->dirroot.'/blog/lib.php');
23 /**
24 * a class for representing searchable information in user metadata
27 class UserSearchDocument extends SearchDocument {
29 /**
30 * constructor
31 * @uses $DB
33 public function __construct(&$userhash, $user_id, $context_id) {
34 global $DB;
36 // generic information; required
37 $doc->docid = $userhash['id'];
38 $doc->documenttype = SEARCH_TYPE_USER;
39 $doc->itemtype = 'user';
40 $doc->contextid = $context_id;
42 $user = $DB->get_record('user', array('id' => $user_id));
43 $doc->title = get_string('user').': '.fullname($user);
44 $doc->date = ($userhash['lastaccess']) ? $userhash['lastaccess'] : time() ;
46 //remove '(ip.ip.ip.ip)' from chat author list
47 $doc->author = $user->id;
48 $doc->contents = $userhash['description'];
49 $doc->url = user_make_link($user_id, 'user');
51 // module specific information; optional
53 // construct the parent class
54 parent::__construct($doc, $data, 0, 0, $user_id, PATH_FOR_SEARCH_TYPE_USER);
58 /**
59 * a class for representing searchable information in user metadata
62 class UserPostSearchDocument extends SearchDocument {
64 /**
65 * constructor
66 * @uses $DB
68 public function __construct(&$post, $user_id, $context_id) {
69 global $DB;
71 // generic information; required
72 $doc->docid = $post['id'];
73 $doc->documenttype = SEARCH_TYPE_USER;
74 $doc->itemtype = 'post';
75 $doc->contextid = $context_id;
77 $user = $DB->get_record('user', array('id' => $user_id));
79 // we cannot call userdate with relevant locale at indexing time.
80 //$doc->title = get_string('post').': '.fullname($user);
81 $doc->title = $post['subject'];
82 $doc->date = $post['created'];
84 //remove '(ip.ip.ip.ip)' from chat author list
85 $doc->author = fullname($user);
86 $doc->contents = $post['description'];
87 // $doc->url = user_make_link($user_id, 'post');
88 $doc->url = user_make_link($post['id'], 'post');
90 // module specific information; optional
92 // construct the parent class
93 parent::__construct($doc, $data, 0, 0, $user_id, PATH_FOR_SEARCH_TYPE_USER);
97 /**
98 * a class for representing searchable information in user metadata
101 class UserBlogAttachmentSearchDocument extends SearchDocument {
104 * constructor
105 * @uses $DB
107 public function __construct(&$post, $context_id) {
108 global $DB;
110 // generic information; required
111 $doc->docid = $post['id'];
112 $doc->documenttype = SEARCH_TYPE_USER;
113 $doc->itemtype = 'attachment';
114 $doc->contextid = $context_id;
116 $user = $DB->get_record('user', 'id', $post['userid']);
118 // we cannot call userdate with relevant locale at indexing time.
119 $doc->title = get_string('file').' : '.$post['subject'];
120 $doc->date = $post['created'];
122 //remove '(ip.ip.ip.ip)' from chat author list
123 $doc->author = fullname($user);
124 $doc->contents = $post['alltext'];
125 $doc->url = user_make_link($post['id'], 'attachment');
127 // module specific information; optional
129 // construct the parent class
130 parent::__construct($doc, $data, 0, 0, $post['userid'], PATH_FOR_SEARCH_TYPE_USER);
136 * constructs a valid link to a user record
137 * @param int $userid the user
138 * @param string $itemtype
139 * @uses $CFG, $DB
140 * @return a well formed link to user information
142 function user_make_link($itemid, $itemtype) {
143 global $CFG, $DB;
145 if ($itemtype == 'user'){
146 return $CFG->wwwroot.'/user/view.php?id='.$itemid;
147 } elseif ($itemtype == 'post') {
148 return $CFG->wwwroot.'/blog/index.php?postid='.$itemid;
149 } elseif ($itemtype == 'attachment') {
150 $post = $DB->get_record('post', array('id' => $itemid));
151 if (!$CFG->slasharguments){
152 return $CFG->wwwroot."/file.php?file=/blog/attachments/{$post->id}/{$post->attachment}";
153 } else {
154 return $CFG->wwwroot."/file.php/blog/attachments/{$post->id}/{$post->attachment}";
156 } else {
157 return null;
162 * part of search engine API
163 * @uses $DB
166 function user_iterator() {
167 global $DB;
169 $users = $DB->get_records('user');
170 return $users;
174 * part of search engine API
175 * @uses $CFG, $DB
176 * @param reference $user a user record
177 * @return an array of documents generated from data
179 function user_get_content_for_index(&$user) {
180 global $CFG, $DB;
182 $documents = array();
184 $userhash = get_object_vars($user);
185 $documents[] = new UserSearchDocument($userhash, $user->id, null);
187 if ($posts = $DB->get_records('post', array('userid' => $user->id), 'created')){
188 foreach($posts as $post){
189 $texts = array();
190 $texts[] = $post->subject;
191 $texts[] = $post->summary;
192 $texts[] = $post->content;
193 $post->description = implode(' ', $texts);
195 // record the attachment if any and physical files can be indexed
196 if (@$CFG->block_search_enable_file_indexing){
197 if ($post->attachment){
198 user_get_physical_file($post, null, false, $documents);
202 $posthash = get_object_vars($post);
203 $documents[] = new UserPostSearchDocument($posthash, $user->id, null);
206 return $documents;
210 * get text from a physical file
211 * @uses $CFG
212 * @param object $post a post to whech the file is attached to
213 * @param boolean $context_id if in future we need recording a context along with the search document, pass it here
214 * @param boolean $getsingle if true, returns a single search document, elsewhere return the array
215 * given as documents increased by one
216 * @param array $documents the array of documents, by ref, where to add the new document.
217 * @return a search document when unique or false.
219 function user_get_physical_file(&$post, $context_id, $getsingle, &$documents = null){
220 global $CFG;
222 // cannot index empty references
223 if (empty($post->attachment)){
224 mtrace("Cannot index, empty reference.");
225 return false;
228 $fileparts = pathinfo($post->attachment);
229 // cannot index unknown or masked types
230 if (empty($fileparts['extension'])) {
231 mtrace("Cannot index without explicit extension.");
232 return false;
235 // cannot index non existent file
236 $file = "{$CFG->dataroot}/blog/attachments/{$post->id}/{$post->attachment}";
237 if (!file_exists($file)){
238 mtrace("Missing attachment file $file : will not be indexed.");
239 return false;
242 $ext = strtolower($fileparts['extension']);
244 // cannot index unallowed or unhandled types
245 if (!preg_match("/\b$ext\b/i", $CFG->block_search_filetypes)) {
246 mtrace($fileparts['extension'] . ' is not an allowed extension for indexing');
247 return false;
249 if (file_exists($CFG->dirroot.'/search/documents/physical_'.$ext.'.php')){
250 include_once($CFG->dirroot.'/search/documents/physical_'.$ext.'.php');
251 $function_name = 'get_text_for_indexing_'.$ext;
252 $directfile = "blog/attachments/{$post->id}/{$post->attachment}";
253 $post->alltext = $function_name($post, $directfile);
254 if (!empty($post->alltext)){
255 if ($getsingle){
256 $posthash = get_object_vars($post);
257 $single = new UserBlogAttachmentSearchDocument($posthash, $context_id);
258 mtrace("finished attachment {$post->attachment} in {$post->title}");
259 return $single;
260 } else {
261 $posthash = get_object_vars($post);
262 $documents[] = new UserBlogAttachmentSearchDocument($posthash, $context_id);
264 mtrace("finished attachment {$post->attachment} in {$post->subject}");
266 } else {
267 mtrace("fulltext handler not found for $ext type");
269 return false;
273 * returns a single user search document
274 * @uses $DB
275 * @param composite $id a unique document id made with
276 * @param itemtype the type of information (session is the only type)
278 function user_single_document($id, $itemtype) {
279 global $DB;
281 if ($itemtype == 'user'){
282 if ($user = $DB->get_record('user', array('id' => $id))){
283 $userhash = get_object_vars($user);
284 return new UserSearchDocument($userhash, $user->id, 'user', null);
286 } elseif ($itemtype == 'post') {
287 if ($post = $DB->get_record('post', array('id' => $id))){
288 $texts = array();
289 $texts[] = $post->subject;
290 $texts[] = $post->summary;
291 $texts[] = $post->content;
292 $post->description = implode(" ", $texts);
293 $posthash = get_object_vars($post);
294 return new UserPostSearchDocument($posthash, $post->userid, 'post', null);
296 } elseif ($itemtype == 'attachment' && @$CFG->block_search_enable_file_indexing) {
297 if ($post = $DB->get_records('post', array('id' => $id))){
298 if ($post->attachment){
299 return user_get_physical_file($post, null, true);
303 return null;
307 * dummy delete function that packs id with itemtype.
308 * this was here for a reason, but I can't remember it at the moment.
311 function user_delete($info, $itemtype) {
312 $object->id = $info;
313 $object->itemtype = $itemtype;
314 return $object;
318 * returns the var names needed to build a sql query for addition/deletions
319 * attachments are indirect records, linked to its post
321 function user_db_names() {
322 //[primary id], [table name], [time created field name], [time modified field name] [itemtype] [select restriction clause]
323 return array(
324 array('id', 'user', 'firstaccess', 'timemodified', 'user'),
325 array('id', 'post', 'created', 'lastmodified', 'post'),
326 array('id', 'post', 'created', 'lastmodified', 'attachment')
331 * this function handles the access policy to contents indexed as searchable documents. If this
332 * function does not exist, the search engine assumes access is allowed.
333 * When this point is reached, we already know that :
334 * - user is legitimate in the surrounding context
335 * - user may be guest and guest access is allowed to the module
336 * - the function may perform local checks within the module information logic
337 * @param string $path the access path to the module script code
338 * @param string $itemtype the information subclassing (usefull for complex modules, defaults to 'standard')
339 * @param int $this_id the item id within the information class denoted by entry_type. In chats, this id
340 * points out a session history which is a close sequence of messages.
341 * @param object $user the user record denoting the user who searches
342 * @param int $group_id the current group used by the user when searching
343 * @uses $CFG, $DB
344 * @return true if access is allowed, false elsewhere
346 function user_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
347 global $CFG, $DB;
349 include_once("{$CFG->dirroot}/{$path}/lib.php");
351 if ($itemtype == 'user'){
352 // get the user
353 $userrecord = $DB->get_record('user', array('id' => $this_id));
355 // we cannot see nothing from unconfirmed users
356 if (!$userrecord->confirmed and !has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))){
357 if (!empty($CFG->search_access_debug)) echo "search reject : unconfirmed user ";
358 return false;
360 } elseif ($itemtype == 'post' || $itemtype == 'attachment'){
361 // get the post
362 $post = $DB->get_record('post', array('id' => $this_id));
363 $userrecord = $DB->get_record('user', array('id' => $post->userid));
365 // we can try using blog visibility check
366 return blog_user_can_view_user_post($user->id, $post);
368 $context = $DB->get_record('context', array('id' => $context_id));
370 return true;
374 * this call back is called when displaying the link for some last post processing
377 function user_link_post_processing($title){
378 global $CFG;
380 if ($CFG->block_search_utf8dir){
381 return mb_convert_encoding($title, 'UTF-8', 'auto');
383 return mb_convert_encoding($title, 'auto', 'UTF-8');