moodle/search/documents/forum_document.php
diml 27af904b85 fixes result list ordering issue
engine give nicer results with adequate pagination.
Adding icon and reference to course origine.

Generalizing replacement of isadmin by doanithing capability check

should contribute to close many global search related issues from

http://tracker.moodle.org/browse/MDL-14646

startpoint
2008-05-31 17:09:59 +00:00

314 lines
10 KiB
PHP

<?php
/**
* Global Search Engine for Moodle
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Michael Campanis (mchampan) [cynnical@gmail.com], Valery Fremaux [valery.fremaux@club-internet.fr] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for forum activity module
* This file contains the mapping between a forum post and it's indexable counterpart,
*
* Functions for iterating and retrieving the necessary records are now also included
* in this file, rather than mod/forum/lib.php
*
*/
/**
* includes and requires
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/mod/forum/lib.php");
/**
* a class for representing searchable information
*
*/
class ForumSearchDocument extends SearchDocument {
/**
* constructor
*/
public function __construct(&$post, $forum_id, $course_id, $itemtype, $context_id) {
// generic information
$doc->docid = $post['id'];
$doc->documenttype = SEARCH_TYPE_FORUM;
$doc->itemtype = $itemtype;
$doc->contextid = $context_id;
$doc->title = $post['subject'];
$user = get_record('user', 'id', $post['userid']);
$doc->author = fullname($user);
$doc->contents = $post['message'];
$doc->date = $post['created'];
$doc->url = forum_make_link($post['discussion'], $post['id']);
// module specific information
$data->forum = $forum_id;
$data->discussion = $post['discussion'];
parent::__construct($doc, $data, $course_id, $post['groupid'], $post['userid'], 'mod/'.SEARCH_TYPE_FORUM);
}
}
/**
* constructs a valid link to a chat content
* @param discussion_id the discussion
* @param post_id the id of a single post
* @return a well formed link to forum message display
*/
function forum_make_link($discussion_id, $post_id) {
global $CFG;
return $CFG->wwwroot.'/mod/forum/discuss.php?d='.$discussion_id.'#'.$post_id;
}
/**
* search standard API
*
*/
function forum_iterator() {
$forums = get_records('forum');
return $forums;
}
/**
* search standard API
* @param forum a forum instance
* @return an array of searchable documents
*/
function forum_get_content_for_index(&$forum) {
$documents = array();
if (!$forum) return $documents;
$posts = forum_get_discussions_fast($forum->id);
mtrace("Found ".count($posts)." discussions to analyse in forum ".$forum->name);
if (!$posts) return $documents;
$coursemodule = get_field('modules', 'id', 'name', 'forum');
$cm = get_record('course_modules', 'course', $forum->course, 'module', $coursemodule, 'instance', $forum->id);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
foreach($posts as $aPost) {
$aPost->itemtype = 'head';
if ($aPost) {
if (!empty($aPost->message)) {
echo "*";
$documents[] = new ForumSearchDocument(get_object_vars($aPost), $forum->id, $forum->course, 'head', $context->id);
}
if ($children = forum_get_child_posts_fast($aPost->id, $forum->id)) {
foreach($children as $aChild) {
echo ".";
$aChild->itemtype = 'post';
if (strlen($aChild->message) > 0) {
$documents[] = new ForumSearchDocument(get_object_vars($aChild), $forum->id, $forum->course, 'post', $context->id);
}
}
}
}
}
mtrace("Finished discussion");
return $documents;
}
/**
* returns a single forum search document based on a forum entry id
* @param id an id for a single information stub
* @param itemtype the type of information
*/
function forum_single_document($id, $itemtype) {
// both known item types are posts so get them the same way
$post = get_record('forum_posts', 'id', $id);
$discussion = get_record('forum_discussions', 'id', $post->discussion);
$coursemodule = get_field('modules', 'id', 'name', 'forum');
$cm = get_record('course_modules', 'course', $discussion->course, 'module', $coursemodule, 'instance', $discussion->forum);
if ($cm){
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
$post->groupid = $discussion->groupid;
return new ForumSearchDocument(get_object_vars($post), $discussion->forum, $discussion->course, $itemtype, $context->id);
}
return null;
}
/**
* dummy delete function that aggregates id with itemtype.
* this was here for a reason, but I can't remember it at the moment.
*
*/
function forum_delete($info, $itemtype) {
$object->id = $info;
$object->itemtype = $itemtype;
return $object;
}
/**
* returns the var names needed to build a sql query for addition/deletions
*
*/
function forum_db_names() {
//[primary id], [table name], [time created field name], [time modified field name]
return array(
array('id', 'forum_posts', 'created', 'modified', 'head', 'parent = 0'),
array('id', 'forum_posts', 'created', 'modified', 'post', 'parent != 0')
);
}
/**
* reworked faster version from /mod/forum/lib.php
* @param forum_id a forum identifier
* @uses CFG, USER
* @return an array of posts
*/
function forum_get_discussions_fast($forum_id) {
global $CFG, $USER;
$timelimit='';
if (!empty($CFG->forum_enabletimedposts)) {
if (!((has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))
and !empty($CFG->admineditalways)) || isteacher(get_field('forum', 'course', 'id', $forum_id)))) {
$now = time();
$timelimit = " AND ((d.timestart = 0 OR d.timestart <= '$now') AND (d.timeend = 0 OR d.timeend > '$now')";
if (!empty($USER->id)) {
$timelimit .= " OR d.userid = '$USER->id'";
}
$timelimit .= ')';
}
}
$query = "
SELECT
p.id,
p.subject,
p.discussion,
p.message,
p.created,
d.groupid,
p.userid,
u.firstname,
u.lastname
FROM
{$CFG->prefix}forum_discussions d
JOIN
{$CFG->prefix}forum_posts p
ON
p.discussion = d.id
JOIN
{$CFG->prefix}user u
ON
p.userid = u.id
WHERE
d.forum = '{$forum_id}' AND
p.parent = 0
$timelimit
ORDER BY
d.timemodified DESC
";
return get_records_sql($query);
}
/**
* reworked faster version from /mod/forum/lib.php
* @param parent the id of the first post within the discussion
* @param forum_id the forum identifier
* @uses CFG
* @return an array of posts
*/
function forum_get_child_posts_fast($parent, $forum_id) {
global $CFG;
$query = "
SELECT
p.id,
p.subject,
p.discussion,
p.message,
p.created,
{$forum_id} AS forum,
p.userid,
d.groupid,
u.firstname,
u.lastname
FROM
{$CFG->prefix}forum_discussions d
JOIN
{$CFG->prefix}forum_posts p
ON
p.discussion = d.id
JOIN
{$CFG->prefix}user u
ON
p.userid = u.id
WHERE
p.parent = '{$parent}'
ORDER BY
p.created ASC
";
return get_records_sql($query);
}
/**
* this function handles the access policy to contents indexed as searchable documents. If this
* function does not exist, the search engine assumes access is allowed.
* When this point is reached, we already know that :
* - user is legitimate in the surrounding context
* - user may be guest and guest access is allowed to the module
* - the function may perform local checks within the module information logic
* @param path the access path to the module script code
* @param itemtype the information subclassing (usefull for complex modules, defaults to 'standard')
* @param this_id the item id within the information class denoted by itemtype. In forums, this id
* points out the individual post.
* @param user the user record denoting the user who searches
* @param group_id the current group used by the user when searching
* @uses CFG, USER
* @return true if access is allowed, false elsewhere
*/
function forum_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
global $CFG, $USER;
include_once("{$CFG->dirroot}/{$path}/lib.php");
// get the forum post and all related stuff
$post = get_record('forum_posts', 'id', $this_id);
$discussion = get_record('forum_discussions', 'id', $post->discussion);
$context = get_record('context', 'id', $context_id);
$cm = get_record('course_modules', 'id', $context->instanceid);
// $cm = get_coursemodule_from_instance('forum', $discussion->forum, $discussion->course);
// $context = get_context_instance(CONTEXT_MODULE, $cm->id);
if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $context)){
if (!empty($CFG->search_access_debug)) echo "search reject : hidden forum resource ";
return false;
}
// approval check : entries should be approved for being viewed, or belongs to the user
if (($post->userid != $USER->id) && !$post->mailed && !has_capability('mod/forum:viewhiddentimeposts', $context)){
if (!empty($CFG->search_access_debug)) echo "search reject : time hidden forum item";
return false;
}
// group check : entries should be in accessible groups
$current_group = get_current_group($discussion->course);
$course = get_record('course', 'id', $discussion->course);
if ($group_id >= 0 && (groupmode($course, $cm) == SEPARATEGROUPS) && ($group_id != $current_group) && !has_capability('mod/forum:viewdiscussionsfromallgroups', $context)){
if (!empty($CFG->search_access_debug)) echo "search reject : separated grouped forum item";
return false;
}
return true;
}
/**
* post processes the url for cleaner output.
* @param string $title
*/
function forum_link_post_processing($title){
// return mb_convert_encoding($title, 'UTF-8', 'auto');
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>