if ($mode) { set_user_preference('forum_displaymode', $mode); } $displaymode = get_user_preferences('forum_displaymode', $CFG->forum_displaymode); if ($parent) { // If flat AND parent, then force nested display this time if ($displaymode == FORUM_MODE_FLATOLDEST or $displaymode == FORUM_MODE_FLATNEWEST) { $displaymode = FORUM_MODE_NESTED; } } else { $parent = $discussion->firstpost; } if (!($post = forum_get_post_full($parent))) { print_error("notexists", 'forum', "{$CFG->wwwroot}/mod/forum/view.php?f={$forum->id}"); } if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) { print_error('noviewdiscussionspermission', 'forum', "{$CFG->wwwroot}/mod/forum/view.php?id={$forum->id}"); } if ($mark == 'read' or $mark == 'unread') { if ($CFG->forum_usermarksread && forum_tp_can_track_forums($forum) && forum_tp_is_tracked($forum)) { if ($mark == 'read') { forum_tp_add_read_record($USER->id, $postid); } else { // unread forum_tp_delete_read_records($USER->id, $postid); } } } $searchform = forum_search_form($course); $forumnode = $PAGE->navigation->find($cm->id, navigation_node::TYPE_ACTIVITY); if (empty($forumnode)) {
/** * @todo Document this function * * @global object * @global object * @uses CONTEXT_MODULE * @return void */ function forum_print_posts_threaded($course, &$cm, $forum, $discussion, $parent, $depth, $reply, $forumtracked, $posts) { global $USER, $CFG; $link = false; if (!empty($posts[$parent->id]->children)) { $posts = $posts[$parent->id]->children; $modcontext = context_module::instance($cm->id); $canviewfullnames = has_capability('moodle/site:viewfullnames', $modcontext); foreach ($posts as $post) { echo '<div class="indent">'; if ($depth > 0) { $ownpost = ($USER->id == $post->userid); $post->subject = format_string($post->subject); $postread = !empty($post->postread); forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link, '', '', $postread, true, $forumtracked); } else { if (!forum_user_can_see_post($forum, $discussion, $post, NULL, $cm)) { echo "</div>\n"; continue; } $by = new stdClass(); $by->name = fullname($post, $canviewfullnames); $by->date = userdate($post->modified); if ($forumtracked) { if (!empty($post->postread)) { $style = '<span class="forumthread read">'; } else { $style = '<span class="forumthread unread">'; } } else { $style = '<span class="forumthread">'; } echo $style."<a name=\"$post->id\"></a>". "<a href=\"discuss.php?d=$post->discussion&parent=$post->id\">".format_string($post->subject,true)."</a> "; print_string("bynameondate", "forum", $by); echo "</span>"; } forum_print_posts_threaded($course, $cm, $forum, $discussion, $post, $depth-1, $reply, $forumtracked, $posts); echo "</div>\n"; } } }
} if ($edit) { $PAGE->navbar->add(get_string('edit', 'forum')); } $PAGE->set_title("{$course->shortname}: {$strdiscussionname} " . format_string($toppost->subject)); $PAGE->set_heading($course->fullname); // #marginalia begin $moodlemia = moodle_marginalia::get_instance(); $miaprofile = $moodlemia->get_profile($PAGE->url->out(false)); if ($miaprofile) { $miaprofile->emit_requires($moodlemia); } // #marginalia end echo $OUTPUT->header(); // checkup if (!empty($parent) && !forum_user_can_see_post($forum, $discussion, $post, null, $cm)) { print_error('cannotreply', 'forum'); } if (empty($parent) && empty($edit) && !forum_user_can_post_discussion($forum, $groupid, -1, $cm, $modcontext)) { print_error('cannotcreatediscussion', 'forum'); } if ($forum->type == 'qanda' && !has_capability('mod/forum:viewqandawithoutposting', $modcontext) && !empty($discussion->id) && !forum_user_has_posted($forum->id, $discussion->id, $USER->id)) { echo $OUTPUT->notification(get_string('qandanotify', 'forum')); } forum_check_throttling($forum, $cm); if (!empty($parent)) { if (!($discussion = $DB->get_record('forum_discussions', array('id' => $parent->discussion)))) { print_error('notpartofdiscussion', 'forum'); } // #marginalia begin $moodlemia = moodle_marginalia::get_instance();
/** * Whether the user can access the document or not. * * @throws \dml_missing_record_exception * @throws \dml_exception * @param int $id Forum post id * @return bool */ public function check_access($id) { global $USER; try { $post = $this->get_post($id); $forum = $this->get_forum($post->forum); $discussion = $this->get_discussion($post->discussion); $cminfo = $this->get_cm('forum', $forum->id, $forum->course); $cm = $cminfo->get_course_module_record(); } catch (\dml_missing_record_exception $ex) { return \core_search\manager::ACCESS_DELETED; } catch (\dml_exception $ex) { return \core_search\manager::ACCESS_DENIED; } // Recheck uservisible although it should have already been checked in core_search. if ($cminfo->uservisible === false) { return \core_search\manager::ACCESS_DENIED; } if (!forum_user_can_see_post($forum, $discussion, $post, $USER, $cm)) { return \core_search\manager::ACCESS_DENIED; } return \core_search\manager::ACCESS_GRANTED; }
/** * This function return the XML rss contents about the forum * It returns false if something is wrong * * @param stdClass $forum the forum object * @param string $sql the SQL used to retrieve the contents from the database * @param array $params the SQL parameters used * @param object $context the context this forum relates to * @return bool|string false if the contents is empty, otherwise the contents of the feed is returned * * @Todo MDL-31129 implement post attachment handling */ function forum_rss_feed_contents($forum, $sql, $params, $context) { global $CFG, $DB, $USER; $status = true; $recs = $DB->get_recordset_sql($sql, $params, 0, $forum->rssarticles); //set a flag. Are we displaying discussions or posts? $isdiscussion = true; if (!empty($forum->rsstype) && $forum->rsstype!=1) { $isdiscussion = false; } if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) { print_error('invalidcoursemodule'); } $formatoptions = new stdClass(); $items = array(); foreach ($recs as $rec) { $item = new stdClass(); $user = new stdClass(); $discussion = new stdClass(); $discussion->id = $rec->discussionid; $discussion->groupid = $rec->groupid; $discussion->timestart = $rec->timestart; $discussion->timeend = $rec->timeend; $post = null; if (!$isdiscussion) { $post = new stdClass(); $post->id = $rec->postid; $post->parent = $rec->postparent; $post->userid = $rec->userid; } if ($isdiscussion && !forum_user_can_see_discussion($forum, $discussion, $context)) { // This is a discussion which the user has no permission to view $item->title = get_string('forumsubjecthidden', 'forum'); $message = get_string('forumbodyhidden', 'forum'); $item->author = get_string('forumauthorhidden', 'forum'); } else if (!$isdiscussion && !forum_user_can_see_post($forum, $discussion, $post, $USER, $cm)) { // This is a post which the user has no permission to view $item->title = get_string('forumsubjecthidden', 'forum'); $message = get_string('forumbodyhidden', 'forum'); $item->author = get_string('forumauthorhidden', 'forum'); } else { // The user must have permission to view if ($isdiscussion && !empty($rec->discussionname)) { $item->title = format_string($rec->discussionname); } else if (!empty($rec->postsubject)) { $item->title = format_string($rec->postsubject); } else { //we should have an item title by now but if we dont somehow then substitute something somewhat meaningful $item->title = format_string($forum->name.' '.userdate($rec->postcreated,get_string('strftimedatetimeshort', 'langconfig'))); } $user->firstname = $rec->userfirstname; $user->lastname = $rec->userlastname; $item->author = fullname($user); $message = file_rewrite_pluginfile_urls($rec->postmessage, 'pluginfile.php', $context->id, 'mod_forum', 'post', $rec->postid); $formatoptions->trusted = $rec->posttrust; } if ($isdiscussion) { $item->link = $CFG->wwwroot."/mod/forum/discuss.php?d=".$rec->discussionid; } else { $item->link = $CFG->wwwroot."/mod/forum/discuss.php?d=".$rec->discussionid."&parent=".$rec->postid; } $formatoptions->trusted = $rec->posttrust; $item->description = format_text($message, $rec->postformat, $formatoptions, $forum->course); //TODO: MDL-31129 implement post attachment handling /*if (!$isdiscussion) { $post_file_area_name = str_replace('//', '/', "$forum->course/$CFG->moddata/forum/$forum->id/$rec->postid"); $post_files = get_directory_list("$CFG->dataroot/$post_file_area_name"); if (!empty($post_files)) { $item->attachments = array(); } }*/ $item->pubdate = $rec->postcreated; $items[] = $item; } $recs->close(); // Create the RSS header. $header = rss_standard_header(strip_tags(format_string($forum->name,true)), $CFG->wwwroot."/mod/forum/view.php?f=".$forum->id, format_string($forum->intro,true)); // TODO: fix format // Now all the RSS items, if there are any. $articles = ''; if (!empty($items)) { $articles = rss_add_items($items); } // Create the RSS footer. $footer = rss_standard_footer(); return $header . $articles . $footer; }
/** * Returns a list of forum posts for a discussion * * @param int $discussionid the post ids * @param string $sortby sort by this element (id, created or modified) * @param string $sortdirection sort direction: ASC or DESC * * @return array the forum post details * @since Moodle 2.7 */ public static function get_forum_discussion_posts($discussionid, $sortby = "created", $sortdirection = "DESC") { global $CFG, $DB, $USER; $warnings = array(); // Validate the parameter. $params = self::validate_parameters(self::get_forum_discussion_posts_parameters(), array('discussionid' => $discussionid, 'sortby' => $sortby, 'sortdirection' => $sortdirection)); // Compact/extract functions are not recommended. $discussionid = $params['discussionid']; $sortby = $params['sortby']; $sortdirection = $params['sortdirection']; $sortallowedvalues = array('id', 'created', 'modified'); if (!in_array($sortby, $sortallowedvalues)) { throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' . 'allowed values are: ' . implode(',', $sortallowedvalues)); } $sortdirection = strtoupper($sortdirection); $directionallowedvalues = array('ASC', 'DESC'); if (!in_array($sortdirection, $directionallowedvalues)) { throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' . 'allowed values are: ' . implode(',', $directionallowedvalues)); } $discussion = $DB->get_record('forum_discussions', array('id' => $discussionid), '*', MUST_EXIST); $forum = $DB->get_record('forum', array('id' => $discussion->forum), '*', MUST_EXIST); $course = $DB->get_record('course', array('id' => $forum->course), '*', MUST_EXIST); $cm = get_coursemodule_from_instance('forum', $forum->id, $course->id, false, MUST_EXIST); // Validate the module context. It checks everything that affects the module visibility (including groupings, etc..). $modcontext = context_module::instance($cm->id); self::validate_context($modcontext); // This require must be here, see mod/forum/discuss.php. require_once $CFG->dirroot . "/mod/forum/lib.php"; // Check they have the view forum capability. require_capability('mod/forum:viewdiscussion', $modcontext, null, true, 'noviewdiscussionspermission', 'forum'); if (!($post = forum_get_post_full($discussion->firstpost))) { throw new moodle_exception('notexists', 'forum'); } // This function check groups, qanda, timed discussions, etc. if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) { throw new moodle_exception('noviewdiscussionspermission', 'forum'); } $canviewfullname = has_capability('moodle/site:viewfullnames', $modcontext); // We will add this field in the response. $canreply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext); $forumtracked = forum_tp_is_tracked($forum); $sort = 'p.' . $sortby . ' ' . $sortdirection; $posts = forum_get_all_discussion_posts($discussion->id, $sort, $forumtracked); foreach ($posts as $pid => $post) { if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) { $warning = array(); $warning['item'] = 'post'; $warning['itemid'] = $post->id; $warning['warningcode'] = '1'; $warning['message'] = 'You can\'t see this post'; $warnings[] = $warning; continue; } // Function forum_get_all_discussion_posts adds postread field. // Note that the value returned can be a boolean or an integer. The WS expects a boolean. if (empty($post->postread)) { $posts[$pid]->postread = false; } else { $posts[$pid]->postread = true; } $posts[$pid]->canreply = $canreply; if (!empty($posts[$pid]->children)) { $posts[$pid]->children = array_keys($posts[$pid]->children); } else { $posts[$pid]->children = array(); } $user = new stdclass(); $user = username_load_fields_from_object($user, $post); $posts[$pid]->userfullname = fullname($user, $canviewfullname); $posts[$pid] = (array) $post; } $result = array(); $result['posts'] = $posts; $result['warnings'] = $warnings; return $result; }
/** * TODO document */ function forum_print_posts_threaded($parent, $courseid, $depth, $ratings, $reply, &$user_read_array, $forumid = 0, $modcontext = NULL) { global $USER, $CFG; $link = false; $ratingsmenuused = false; $istracking = forum_tp_can_track_forums($forumid) && forum_tp_is_tracked($forumid); if ($posts = forum_get_child_posts($parent, $forumid)) { $canviewfullnames = has_capability('moodle/site:viewfullnames', $modcontext); foreach ($posts as $post) { echo '<div class="indent">'; if ($depth > 0) { $ownpost = $USER->id == $post->userid; $post->subject = format_string($post->subject); $post->modcontext = $modcontext; if (forum_print_post($post, $courseid, $ownpost, $reply, $link, $ratings, '', '', isset($user_read_array[$post->id]) || forum_tp_is_post_old($post))) { $ratingsmenuused = true; } } else { if (!forum_user_can_see_post($post->forum, $post->discussion, $post)) { continue; } $by = new object(); $by->name = fullname($post, $canviewfullnames); $by->date = userdate($post->modified); if ($istracking) { if (isset($user_read_array[$post->id]) || forum_tp_is_post_old($post)) { $style = '<span class="forumthread read">'; } else { $style = '<span class="forumthread unread">'; } } else { $style = '<span class="forumthread">'; } echo $style . "<a name=\"{$post->id}\"></a>" . "<a href=\"discuss.php?d={$post->discussion}&parent={$post->id}\">" . format_string($post->subject, true) . "</a> "; print_string("bynameondate", "forum", $by); echo "</span>"; } if (forum_print_posts_threaded($post->id, $courseid, $depth - 1, $ratings, $reply, $user_read_array, $forumid, $modcontext)) { $ratingsmenuused = true; } echo "</div>\n"; } } return $ratingsmenuused; }
/** * Checks to see if a user can view a particular post. * * @deprecated since Moodle 2.4 use forum_user_can_see_post() instead * * @param object $post * @param object $course * @param object $cm * @param object $forum * @param object $discussion * @param object $user * @return boolean */ function forum_user_can_view_post($post, $course, $cm, $forum, $discussion, $user = null) { debugging('forum_user_can_view_post() is deprecated. Please use forum_user_can_see_post() instead.', DEBUG_DEVELOPER); return forum_user_can_see_post($forum, $discussion, $post, $user, $cm); }
/** * Returns a list of forum posts for a discussion * * @param int $discussionid the post ids * @param string $sortby sort by this element (id, created or modified) * @param string $sortdirection sort direction: ASC or DESC * * @return array the forum post details * @since Moodle 2.7 */ public static function get_forum_discussion_posts($discussionid, $sortby = "created", $sortdirection = "DESC") { global $CFG, $DB, $USER; $posts = array(); $warnings = array(); // Validate the parameter. $params = self::validate_parameters(self::get_forum_discussion_posts_parameters(), array( 'discussionid' => $discussionid, 'sortby' => $sortby, 'sortdirection' => $sortdirection)); // Compact/extract functions are not recommended. $discussionid = $params['discussionid']; $sortby = $params['sortby']; $sortdirection = $params['sortdirection']; $sortallowedvalues = array('id', 'created', 'modified'); if (!in_array($sortby, $sortallowedvalues)) { throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' . 'allowed values are: ' . implode(',', $sortallowedvalues)); } $sortdirection = strtoupper($sortdirection); $directionallowedvalues = array('ASC', 'DESC'); if (!in_array($sortdirection, $directionallowedvalues)) { throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' . 'allowed values are: ' . implode(',', $directionallowedvalues)); } $discussion = $DB->get_record('forum_discussions', array('id' => $discussionid), '*', MUST_EXIST); $forum = $DB->get_record('forum', array('id' => $discussion->forum), '*', MUST_EXIST); $course = $DB->get_record('course', array('id' => $forum->course), '*', MUST_EXIST); $cm = get_coursemodule_from_instance('forum', $forum->id, $course->id, false, MUST_EXIST); // Validate the module context. It checks everything that affects the module visibility (including groupings, etc..). $modcontext = context_module::instance($cm->id); self::validate_context($modcontext); // This require must be here, see mod/forum/discuss.php. require_once($CFG->dirroot . "/mod/forum/lib.php"); // Check they have the view forum capability. require_capability('mod/forum:viewdiscussion', $modcontext, null, true, 'noviewdiscussionspermission', 'forum'); if (! $post = forum_get_post_full($discussion->firstpost)) { throw new moodle_exception('notexists', 'forum'); } // This function check groups, qanda, timed discussions, etc. if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) { throw new moodle_exception('noviewdiscussionspermission', 'forum'); } $canviewfullname = has_capability('moodle/site:viewfullnames', $modcontext); // We will add this field in the response. $canreply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext); $forumtracked = forum_tp_is_tracked($forum); $sort = 'p.' . $sortby . ' ' . $sortdirection; $allposts = forum_get_all_discussion_posts($discussion->id, $sort, $forumtracked); foreach ($allposts as $post) { if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) { $warning = array(); $warning['item'] = 'post'; $warning['itemid'] = $post->id; $warning['warningcode'] = '1'; $warning['message'] = 'You can\'t see this post'; $warnings[] = $warning; continue; } // Function forum_get_all_discussion_posts adds postread field. // Note that the value returned can be a boolean or an integer. The WS expects a boolean. if (empty($post->postread)) { $post->postread = false; } else { $post->postread = true; } $post->canreply = $canreply; if (!empty($post->children)) { $post->children = array_keys($post->children); } else { $post->children = array(); } $user = new stdclass(); $user->id = $post->userid; $user = username_load_fields_from_object($user, $post); $post->userfullname = fullname($user, $canviewfullname); // We can have post written by users that are deleted. In this case, those users don't have a valid context. $usercontext = context_user::instance($user->id, IGNORE_MISSING); if ($usercontext) { $post->userpictureurl = moodle_url::make_webservice_pluginfile_url( $usercontext->id, 'user', 'icon', null, '/', 'f1')->out(false); } else { $post->userpictureurl = ''; } // Rewrite embedded images URLs. list($post->message, $post->messageformat) = external_format_text($post->message, $post->messageformat, $modcontext->id, 'mod_forum', 'post', $post->id); // List attachments. if (!empty($post->attachment)) { $post->attachments = array(); $fs = get_file_storage(); if ($files = $fs->get_area_files($modcontext->id, 'mod_forum', 'attachment', $post->id, "filename", false)) { foreach ($files as $file) { $filename = $file->get_filename(); $fileurl = moodle_url::make_webservice_pluginfile_url( $modcontext->id, 'mod_forum', 'attachment', $post->id, '/', $filename); $post->attachments[] = array( 'filename' => $filename, 'mimetype' => $file->get_mimetype(), 'fileurl' => $fileurl->out(false) ); } } } $posts[] = $post; } $result = array(); $result['posts'] = $posts; $result['warnings'] = $warnings; return $result; }