MDL-64820 forum: deprecate forum print functions

This commit is contained in:
Ryan Wyllie
2019-03-22 09:31:21 +08:00
parent 9ea78fd041
commit 2e19ca183b
2 changed files with 911 additions and 884 deletions
+892
View File
@@ -410,3 +410,895 @@ function forum_cron() {
debugging("forum_cron() has been deprecated and replaced with new tasks. Please uses these instead.",
DEBUG_DEVELOPER);
}
/**
* Prints a forum discussion
*
* @uses CONTEXT_MODULE
* @uses FORUM_MODE_FLATNEWEST
* @uses FORUM_MODE_FLATOLDEST
* @uses FORUM_MODE_THREADED
* @uses FORUM_MODE_NESTED
* @param stdClass $course
* @param stdClass $cm
* @param stdClass $forum
* @param stdClass $discussion
* @param stdClass $post
* @param int $mode
* @param mixed $canreply
* @param bool $canrate
* @deprecated since Moodle 3.7
*/
function forum_print_discussion($course, $cm, $forum, $discussion, $post, $mode, $canreply=NULL, $canrate=false) {
debugging('forum_print_discussion() has been deprecated, please use \mod_forum\local\renderers\discussion instead.', DEBUG_DEVELOPER);
global $USER, $CFG;
require_once($CFG->dirroot.'/rating/lib.php');
$ownpost = (isloggedin() && $USER->id == $post->userid);
$modcontext = context_module::instance($cm->id);
if ($canreply === NULL) {
$reply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext);
} else {
$reply = $canreply;
}
// $cm holds general cache for forum functions
$cm->cache = new stdClass;
$cm->cache->groups = groups_get_all_groups($course->id, 0, $cm->groupingid);
$cm->cache->usersgroups = array();
$posters = array();
// preload all posts - TODO: improve...
if ($mode == FORUM_MODE_FLATNEWEST) {
$sort = "p.created DESC";
} else {
$sort = "p.created ASC";
}
$forumtracked = forum_tp_is_tracked($forum);
$posts = forum_get_all_discussion_posts($discussion->id, $sort, $forumtracked);
$post = $posts[$post->id];
foreach ($posts as $pid=>$p) {
$posters[$p->userid] = $p->userid;
}
// preload all groups of ppl that posted in this discussion
if ($postersgroups = groups_get_all_groups($course->id, $posters, $cm->groupingid, 'gm.id, gm.groupid, gm.userid')) {
foreach($postersgroups as $pg) {
if (!isset($cm->cache->usersgroups[$pg->userid])) {
$cm->cache->usersgroups[$pg->userid] = array();
}
$cm->cache->usersgroups[$pg->userid][$pg->groupid] = $pg->groupid;
}
unset($postersgroups);
}
//load ratings
if ($forum->assessed != RATING_AGGREGATE_NONE) {
$ratingoptions = new stdClass;
$ratingoptions->context = $modcontext;
$ratingoptions->component = 'mod_forum';
$ratingoptions->ratingarea = 'post';
$ratingoptions->items = $posts;
$ratingoptions->aggregate = $forum->assessed;//the aggregation method
$ratingoptions->scaleid = $forum->scale;
$ratingoptions->userid = $USER->id;
if ($forum->type == 'single' or !$discussion->id) {
$ratingoptions->returnurl = "$CFG->wwwroot/mod/forum/view.php?id=$cm->id";
} else {
$ratingoptions->returnurl = "$CFG->wwwroot/mod/forum/discuss.php?d=$discussion->id";
}
$ratingoptions->assesstimestart = $forum->assesstimestart;
$ratingoptions->assesstimefinish = $forum->assesstimefinish;
$rm = new rating_manager();
$posts = $rm->get_ratings($ratingoptions);
}
$post->forum = $forum->id; // Add the forum id to the post object, later used by forum_print_post
$post->forumtype = $forum->type;
$post->subject = format_string($post->subject);
$postread = !empty($post->postread);
forum_print_post_start($post);
forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, false,
'', '', $postread, true, $forumtracked);
switch ($mode) {
case FORUM_MODE_FLATOLDEST :
case FORUM_MODE_FLATNEWEST :
default:
forum_print_posts_flat($course, $cm, $forum, $discussion, $post, $mode, $reply, $forumtracked, $posts);
break;
case FORUM_MODE_THREADED :
forum_print_posts_threaded($course, $cm, $forum, $discussion, $post, 0, $reply, $forumtracked, $posts);
break;
case FORUM_MODE_NESTED :
forum_print_posts_nested($course, $cm, $forum, $discussion, $post, $reply, $forumtracked, $posts);
break;
}
forum_print_post_end($post);
}
/**
* Return a static array of posts that are open.
*
* @return array
* @deprecated since Moodle 3.7
*/
function forum_post_nesting_cache() {
debugging('forum_post_nesting_cache() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
static $nesting = array();
return $nesting;
}
/**
* Return true for the first time this post was started
*
* @param int $id The id of the post to start
* @return bool
* @deprecated since Moodle 3.7
*/
function forum_should_start_post_nesting($id) {
debugging('forum_should_start_post_nesting() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
$cache = forum_post_nesting_cache();
if (!array_key_exists($id, $cache)) {
$cache[$id] = 1;
return true;
} else {
$cache[$id]++;
return false;
}
}
/**
* Return true when all the opens are nested with a close.
*
* @param int $id The id of the post to end
* @return bool
* @deprecated since Moodle 3.7
*/
function forum_should_end_post_nesting($id) {
debugging('forum_should_end_post_nesting() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
$cache = forum_post_nesting_cache();
if (!array_key_exists($id, $cache)) {
return true;
} else {
$cache[$id]--;
if ($cache[$id] == 0) {
unset($cache[$id]);
return true;
}
}
return false;
}
/**
* Start a forum post container
*
* @param object $post The post to print.
* @param bool $return Return the string or print it
* @return string
* @deprecated since Moodle 3.7
*/
function forum_print_post_start($post, $return = false) {
debugging('forum_print_post_start() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
$output = '';
if (forum_should_start_post_nesting($post->id)) {
$attributes = [
'id' => 'p'.$post->id,
'tabindex' => -1,
'class' => 'relativelink'
];
$output .= html_writer::start_tag('article', $attributes);
}
if ($return) {
return $output;
}
echo $output;
return;
}
/**
* End a forum post container
*
* @param object $post The post to print.
* @param bool $return Return the string or print it
* @return string
* @deprecated since Moodle 3.7
*/
function forum_print_post_end($post, $return = false) {
debugging('forum_print_post_end() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
$output = '';
if (forum_should_end_post_nesting($post->id)) {
$output .= html_writer::end_tag('article');
}
if ($return) {
return $output;
}
echo $output;
return;
}
/**
* Print a forum post
* This function should always be surrounded with calls to forum_print_post_start
* and forum_print_post_end to create the surrounding container for the post.
* Replies can be nested before forum_print_post_end and should reflect the structure of
* thread.
*
* @global object
* @global object
* @uses FORUM_MODE_THREADED
* @uses PORTFOLIO_FORMAT_PLAINHTML
* @uses PORTFOLIO_FORMAT_FILE
* @uses PORTFOLIO_FORMAT_RICHHTML
* @uses PORTFOLIO_ADD_TEXT_LINK
* @uses CONTEXT_MODULE
* @param object $post The post to print.
* @param object $discussion
* @param object $forum
* @param object $cm
* @param object $course
* @param boolean $ownpost Whether this post belongs to the current user.
* @param boolean $reply Whether to print a 'reply' link at the bottom of the message.
* @param boolean $link Just print a shortened version of the post as a link to the full post.
* @param string $footer Extra stuff to print after the message.
* @param string $highlight Space-separated list of terms to highlight.
* @param int $post_read true, false or -99. If we already know whether this user
* has read this post, pass that in, otherwise, pass in -99, and this
* function will work it out.
* @param boolean $dummyifcantsee When forum_user_can_see_post says that
* the current user can't see this post, if this argument is true
* (the default) then print a dummy 'you can't see this post' post.
* If false, don't output anything at all.
* @param bool|null $istracked
* @return void
* @deprecated since Moodle 3.7
*/
function forum_print_post($post, $discussion, $forum, &$cm, $course, $ownpost=false, $reply=false, $link=false,
$footer="", $highlight="", $postisread=null, $dummyifcantsee=true, $istracked=null, $return=false) {
debugging('forum_print_post() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
global $USER, $CFG, $OUTPUT;
require_once($CFG->libdir . '/filelib.php');
// String cache
static $str;
// This is an extremely hacky way to ensure we only print the 'unread' anchor
// the first time we encounter an unread post on a page. Ideally this would
// be moved into the caller somehow, and be better testable. But at the time
// of dealing with this bug, this static workaround was the most surgical and
// it fits together with only printing th unread anchor id once on a given page.
static $firstunreadanchorprinted = false;
$modcontext = context_module::instance($cm->id);
$post->course = $course->id;
$post->forum = $forum->id;
$post->message = file_rewrite_pluginfile_urls($post->message, 'pluginfile.php', $modcontext->id, 'mod_forum', 'post', $post->id);
if (!empty($CFG->enableplagiarism)) {
require_once($CFG->libdir.'/plagiarismlib.php');
$post->message .= plagiarism_get_links(array('userid' => $post->userid,
'content' => $post->message,
'cmid' => $cm->id,
'course' => $post->course,
'forum' => $post->forum));
}
// caching
if (!isset($cm->cache)) {
$cm->cache = new stdClass;
}
if (!isset($cm->cache->caps)) {
$cm->cache->caps = array();
$cm->cache->caps['mod/forum:viewdiscussion'] = has_capability('mod/forum:viewdiscussion', $modcontext);
$cm->cache->caps['moodle/site:viewfullnames'] = has_capability('moodle/site:viewfullnames', $modcontext);
$cm->cache->caps['mod/forum:editanypost'] = has_capability('mod/forum:editanypost', $modcontext);
$cm->cache->caps['mod/forum:splitdiscussions'] = has_capability('mod/forum:splitdiscussions', $modcontext);
$cm->cache->caps['mod/forum:deleteownpost'] = has_capability('mod/forum:deleteownpost', $modcontext);
$cm->cache->caps['mod/forum:deleteanypost'] = has_capability('mod/forum:deleteanypost', $modcontext);
$cm->cache->caps['mod/forum:viewanyrating'] = has_capability('mod/forum:viewanyrating', $modcontext);
$cm->cache->caps['mod/forum:exportpost'] = has_capability('mod/forum:exportpost', $modcontext);
$cm->cache->caps['mod/forum:exportownpost'] = has_capability('mod/forum:exportownpost', $modcontext);
}
if (!isset($cm->uservisible)) {
$cm->uservisible = \core_availability\info_module::is_user_visible($cm, 0, false);
}
if ($istracked && is_null($postisread)) {
$postisread = forum_tp_is_post_read($USER->id, $post);
}
if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm, false)) {
// Do _not_ check the deleted flag - we need to display a different UI.
$output = '';
if (!$dummyifcantsee) {
if ($return) {
return $output;
}
echo $output;
return;
}
$output .= html_writer::start_tag('div', array('class' => 'forumpost clearfix',
'aria-label' => get_string('hiddenforumpost', 'forum')));
$output .= html_writer::start_tag('header', array('class' => 'row header'));
$output .= html_writer::tag('div', '', array('class' => 'left picture', 'role' => 'presentation')); // Picture.
if ($post->parent) {
$output .= html_writer::start_tag('div', array('class' => 'topic'));
} else {
$output .= html_writer::start_tag('div', array('class' => 'topic starter'));
}
$output .= html_writer::tag('div', get_string('forumsubjecthidden','forum'), array('class' => 'subject',
'role' => 'header',
'id' => ('headp' . $post->id))); // Subject.
$authorclasses = array('class' => 'author');
$output .= html_writer::tag('address', get_string('forumauthorhidden', 'forum'), $authorclasses); // Author.
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('header'); // Header.
$output .= html_writer::start_tag('div', array('class'=>'row'));
$output .= html_writer::tag('div', ' ', array('class'=>'left side')); // Groups
$output .= html_writer::tag('div', get_string('forumbodyhidden','forum'), array('class'=>'content')); // Content
$output .= html_writer::end_tag('div'); // row
$output .= html_writer::end_tag('div'); // forumpost
if ($return) {
return $output;
}
echo $output;
return;
}
if (!empty($post->deleted)) {
// Note: Posts marked as deleted are still returned by the above forum_user_can_post because it is required for
// nesting of posts.
$output = '';
if (!$dummyifcantsee) {
if ($return) {
return $output;
}
echo $output;
return;
}
$output .= html_writer::start_tag('div', [
'class' => 'forumpost clearfix',
'aria-label' => get_string('forumbodydeleted', 'forum'),
]);
$output .= html_writer::start_tag('header', array('class' => 'row header'));
$output .= html_writer::tag('div', '', array('class' => 'left picture', 'role' => 'presentation'));
$classes = ['topic'];
if (!empty($post->parent)) {
$classes[] = 'starter';
}
$output .= html_writer::start_tag('div', ['class' => implode(' ', $classes)]);
// Subject.
$output .= html_writer::tag('div', get_string('forumsubjectdeleted', 'forum'), [
'class' => 'subject',
'role' => 'header',
'id' => ('headp' . $post->id)
]);
// Author.
$output .= html_writer::tag('address', '', ['class' => 'author']);
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('header'); // End header.
$output .= html_writer::start_tag('div', ['class' => 'row']);
$output .= html_writer::tag('div', ' ', ['class' => 'left side']); // Groups.
$output .= html_writer::tag('div', get_string('forumbodydeleted', 'forum'), ['class' => 'content']); // Content.
$output .= html_writer::end_tag('div'); // End row.
$output .= html_writer::end_tag('div'); // End forumpost.
if ($return) {
return $output;
}
echo $output;
return;
}
if (empty($str)) {
$str = new stdClass;
$str->edit = get_string('edit', 'forum');
$str->delete = get_string('delete', 'forum');
$str->reply = get_string('reply', 'forum');
$str->parent = get_string('parent', 'forum');
$str->pruneheading = get_string('pruneheading', 'forum');
$str->prune = get_string('prune', 'forum');
$str->displaymode = get_user_preferences('forum_displaymode', $CFG->forum_displaymode);
$str->markread = get_string('markread', 'forum');
$str->markunread = get_string('markunread', 'forum');
}
$discussionlink = new moodle_url('/mod/forum/discuss.php', array('d'=>$post->discussion));
// Build an object that represents the posting user
$postuser = new stdClass;
$postuserfields = explode(',', user_picture::fields());
$postuser = username_load_fields_from_object($postuser, $post, null, $postuserfields);
$postuser->id = $post->userid;
$postuser->fullname = fullname($postuser, $cm->cache->caps['moodle/site:viewfullnames']);
$postuser->profilelink = new moodle_url('/user/view.php', array('id'=>$post->userid, 'course'=>$course->id));
// Prepare the groups the posting user belongs to
if (isset($cm->cache->usersgroups)) {
$groups = array();
if (isset($cm->cache->usersgroups[$post->userid])) {
foreach ($cm->cache->usersgroups[$post->userid] as $gid) {
$groups[$gid] = $cm->cache->groups[$gid];
}
}
} else {
$groups = groups_get_all_groups($course->id, $post->userid, $cm->groupingid);
}
// Prepare the attachements for the post, files then images
list($attachments, $attachedimages) = forum_print_attachments($post, $cm, 'separateimages');
// Determine if we need to shorten this post
$shortenpost = ($link && (strlen(strip_tags($post->message)) > $CFG->forum_longpost));
// Prepare an array of commands
$commands = array();
// Add a permalink.
$permalink = new moodle_url($discussionlink);
$permalink->set_anchor('p' . $post->id);
$commands[] = array('url' => $permalink, 'text' => get_string('permalink', 'forum'), 'attributes' => ['rel' => 'bookmark']);
// SPECIAL CASE: The front page can display a news item post to non-logged in users.
// Don't display the mark read / unread controls in this case.
if ($istracked && $CFG->forum_usermarksread && isloggedin()) {
$url = new moodle_url($discussionlink, array('postid'=>$post->id, 'mark'=>'unread'));
$text = $str->markunread;
if (!$postisread) {
$url->param('mark', 'read');
$text = $str->markread;
}
if ($str->displaymode == FORUM_MODE_THREADED) {
$url->param('parent', $post->parent);
} else {
$url->set_anchor('p'.$post->id);
}
$commands[] = array('url'=>$url, 'text'=>$text, 'attributes' => ['rel' => 'bookmark']);
}
// Zoom in to the parent specifically
if ($post->parent) {
$url = new moodle_url($discussionlink);
if ($str->displaymode == FORUM_MODE_THREADED) {
$url->param('parent', $post->parent);
} else {
$url->set_anchor('p'.$post->parent);
}
$commands[] = array('url'=>$url, 'text'=>$str->parent, 'attributes' => ['rel' => 'bookmark']);
}
// Hack for allow to edit news posts those are not displayed yet until they are displayed
$age = time() - $post->created;
if (!$post->parent && $forum->type == 'news' && $discussion->timestart > time()) {
$age = 0;
}
if ($forum->type == 'single' and $discussion->firstpost == $post->id) {
if (has_capability('moodle/course:manageactivities', $modcontext)) {
// The first post in single simple is the forum description.
$commands[] = array('url'=>new moodle_url('/course/modedit.php', array('update'=>$cm->id, 'sesskey'=>sesskey(), 'return'=>1)), 'text'=>$str->edit);
}
} else if (($ownpost && $age < $CFG->maxeditingtime) || $cm->cache->caps['mod/forum:editanypost']) {
$commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('edit'=>$post->id)), 'text'=>$str->edit);
}
if ($cm->cache->caps['mod/forum:splitdiscussions'] && $post->parent && $forum->type != 'single') {
$commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('prune'=>$post->id)), 'text'=>$str->prune, 'title'=>$str->pruneheading);
}
if ($forum->type == 'single' and $discussion->firstpost == $post->id) {
// Do not allow deleting of first post in single simple type.
} else if (($ownpost && $age < $CFG->maxeditingtime && $cm->cache->caps['mod/forum:deleteownpost']) || $cm->cache->caps['mod/forum:deleteanypost']) {
$commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('delete'=>$post->id)), 'text'=>$str->delete);
}
if ($reply) {
$commands[] = array('url'=>new moodle_url('/mod/forum/post.php#mformforum', array('reply'=>$post->id)), 'text'=>$str->reply);
}
if ($CFG->enableportfolios && ($cm->cache->caps['mod/forum:exportpost'] || ($ownpost && $cm->cache->caps['mod/forum:exportownpost']))) {
$p = array('postid' => $post->id);
require_once($CFG->libdir.'/portfoliolib.php');
$button = new portfolio_add_button();
$button->set_callback_options('forum_portfolio_caller', array('postid' => $post->id), 'mod_forum');
if (empty($attachments)) {
$button->set_formats(PORTFOLIO_FORMAT_PLAINHTML);
} else {
$button->set_formats(PORTFOLIO_FORMAT_RICHHTML);
}
$porfoliohtml = $button->to_html(PORTFOLIO_ADD_TEXT_LINK);
if (!empty($porfoliohtml)) {
$commands[] = $porfoliohtml;
}
}
// Finished building commands
// Begin output
$output = '';
if ($istracked) {
if ($postisread) {
$forumpostclass = ' read';
} else {
$forumpostclass = ' unread';
// If this is the first unread post printed then give it an anchor and id of unread.
if (!$firstunreadanchorprinted) {
$output .= html_writer::tag('a', '', array('id' => 'unread'));
$firstunreadanchorprinted = true;
}
}
} else {
// ignore trackign status if not tracked or tracked param missing
$forumpostclass = '';
}
$topicclass = '';
if (empty($post->parent)) {
$topicclass = ' firstpost starter';
}
if (!empty($post->lastpost)) {
$forumpostclass .= ' lastpost';
}
// Flag to indicate whether we should hide the author or not.
$authorhidden = forum_is_author_hidden($post, $forum);
$postbyuser = new stdClass;
$postbyuser->post = $post->subject;
$postbyuser->user = $postuser->fullname;
$discussionbyuser = get_string('postbyuser', 'forum', $postbyuser);
// Begin forum post.
$output .= html_writer::start_div('forumpost clearfix' . $forumpostclass . $topicclass,
['aria-label' => $discussionbyuser]);
// Begin header row.
$output .= html_writer::start_tag('header', ['class' => 'row header clearfix']);
// User picture.
if (!$authorhidden) {
$picture = $OUTPUT->user_picture($postuser, ['courseid' => $course->id]);
$output .= html_writer::div($picture, 'left picture', ['role' => 'presentation']);
$topicclass = 'topic' . $topicclass;
}
// Begin topic column.
$output .= html_writer::start_div($topicclass);
$postsubject = $post->subject;
if (empty($post->subjectnoformat)) {
$postsubject = format_string($postsubject);
}
$output .= html_writer::div($postsubject, 'subject', ['role' => 'heading', 'aria-level' => '1', 'id' => ('headp' . $post->id)]);
if ($authorhidden) {
$bytext = userdate_htmltime($post->created);
} else {
$by = new stdClass();
$by->date = userdate_htmltime($post->created);
$by->name = html_writer::link($postuser->profilelink, $postuser->fullname);
$bytext = get_string('bynameondate', 'forum', $by);
}
$bytextoptions = [
'class' => 'author'
];
$output .= html_writer::tag('address', $bytext, $bytextoptions);
// End topic column.
$output .= html_writer::end_div();
// End header row.
$output .= html_writer::end_tag('header');
// Row with the forum post content.
$output .= html_writer::start_div('row maincontent clearfix');
// Show if author is not hidden or we have groups.
if (!$authorhidden || $groups) {
$output .= html_writer::start_div('left');
$groupoutput = '';
if ($groups) {
$groupoutput = print_group_picture($groups, $course->id, false, true, true);
}
if (empty($groupoutput)) {
$groupoutput = '&nbsp;';
}
$output .= html_writer::div($groupoutput, 'grouppictures');
$output .= html_writer::end_div(); // Left side.
}
$output .= html_writer::start_tag('div', array('class'=>'no-overflow'));
$output .= html_writer::start_tag('div', array('class'=>'content'));
$options = new stdClass;
$options->para = false;
$options->trusted = $post->messagetrust;
$options->context = $modcontext;
if ($shortenpost) {
// Prepare shortened version by filtering the text then shortening it.
$postclass = 'shortenedpost';
$postcontent = format_text($post->message, $post->messageformat, $options);
$postcontent = shorten_text($postcontent, $CFG->forum_shortpost);
$postcontent .= html_writer::link($discussionlink, get_string('readtherest', 'forum'));
$postcontent .= html_writer::tag('div', '('.get_string('numwords', 'moodle', count_words($post->message)).')',
array('class'=>'post-word-count'));
} else {
// Prepare whole post
$postclass = 'fullpost';
$postcontent = format_text($post->message, $post->messageformat, $options, $course->id);
if (!empty($highlight)) {
$postcontent = highlight($highlight, $postcontent);
}
if (!empty($forum->displaywordcount)) {
$postcontent .= html_writer::tag('div', get_string('numwords', 'moodle', count_words($postcontent)),
array('class'=>'post-word-count'));
}
$postcontent .= html_writer::tag('div', $attachedimages, array('class'=>'attachedimages'));
}
if (\core_tag_tag::is_enabled('mod_forum', 'forum_posts')) {
$postcontent .= $OUTPUT->tag_list(core_tag_tag::get_item_tags('mod_forum', 'forum_posts', $post->id), null, 'forum-tags');
}
// Output the post content
$output .= html_writer::tag('div', $postcontent, array('class'=>'posting '.$postclass));
$output .= html_writer::end_tag('div'); // Content
$output .= html_writer::end_tag('div'); // Content mask
$output .= html_writer::end_tag('div'); // Row
$output .= html_writer::start_tag('nav', array('class' => 'row side'));
$output .= html_writer::tag('div','&nbsp;', array('class'=>'left'));
$output .= html_writer::start_tag('div', array('class'=>'options clearfix'));
if (!empty($attachments)) {
$output .= html_writer::tag('div', $attachments, array('class' => 'attachments'));
}
// Output ratings
if (!empty($post->rating)) {
$output .= html_writer::tag('div', $OUTPUT->render($post->rating), array('class'=>'forum-post-rating'));
}
// Output the commands
$commandhtml = array();
foreach ($commands as $command) {
if (is_array($command)) {
$attributes = ['class' => 'nav-item nav-link'];
if (isset($command['attributes'])) {
$attributes = array_merge($attributes, $command['attributes']);
}
$commandhtml[] = html_writer::link($command['url'], $command['text'], $attributes);
} else {
$commandhtml[] = $command;
}
}
$output .= html_writer::tag('div', implode(' ', $commandhtml), array('class' => 'commands nav'));
// Output link to post if required
if ($link) {
if (forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext)) {
$langstring = 'discussthistopic';
} else {
$langstring = 'viewthediscussion';
}
if ($post->replies == 1) {
$replystring = get_string('repliesone', 'forum', $post->replies);
} else {
$replystring = get_string('repliesmany', 'forum', $post->replies);
}
if (!empty($discussion->unread) && $discussion->unread !== '-') {
$replystring .= ' <span class="sep">/</span> <span class="unread">';
$unreadlink = new moodle_url($discussionlink, null, 'unread');
if ($discussion->unread == 1) {
$replystring .= html_writer::link($unreadlink, get_string('unreadpostsone', 'forum'));
} else {
$replystring .= html_writer::link($unreadlink, get_string('unreadpostsnumber', 'forum', $discussion->unread));
}
$replystring .= '</span>';
}
$output .= html_writer::start_tag('div', array('class'=>'link'));
$output .= html_writer::link($discussionlink, get_string($langstring, 'forum'));
$output .= '&nbsp;('.$replystring.')';
$output .= html_writer::end_tag('div'); // link
}
// Output footer if required
if ($footer) {
$output .= html_writer::tag('div', $footer, array('class'=>'footer'));
}
// Close remaining open divs
$output .= html_writer::end_tag('div'); // content
$output .= html_writer::end_tag('nav'); // row
$output .= html_writer::end_tag('div'); // forumpost
// Mark the forum post as read if required
if ($istracked && !$CFG->forum_usermarksread && !$postisread) {
forum_tp_mark_post_read($USER->id, $post);
}
if ($return) {
return $output;
}
echo $output;
return;
}
/**
* @global object
* @global object
* @uses FORUM_MODE_FLATNEWEST
* @param object $course
* @param object $cm
* @param object $forum
* @param object $discussion
* @param object $post
* @param object $mode
* @param bool $reply
* @param bool $forumtracked
* @param array $posts
* @return void
* @deprecated since Moodle 3.7
*/
function forum_print_posts_flat($course, &$cm, $forum, $discussion, $post, $mode, $reply, $forumtracked, $posts) {
debugging('forum_print_posts_flat() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
global $USER, $CFG;
$link = false;
foreach ($posts as $post) {
if (!$post->parent) {
continue;
}
$post->subject = format_string($post->subject);
$ownpost = ($USER->id == $post->userid);
$postread = !empty($post->postread);
forum_print_post_start($post);
forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
'', '', $postread, true, $forumtracked);
forum_print_post_end($post);
}
}
/**
* @todo Document this function
*
* @global object
* @global object
* @uses CONTEXT_MODULE
* @return void
* @deprecated since Moodle 3.7
*/
function forum_print_posts_threaded($course, &$cm, $forum, $discussion, $parent, $depth, $reply, $forumtracked, $posts) {
debugging('forum_print_posts_threaded() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
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_start($post);
forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
'', '', $postread, true, $forumtracked);
forum_print_post_end($post);
} else {
if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm, true)) {
if (forum_user_can_see_post($forum, $discussion, $post, null, $cm, false)) {
// This post has been deleted but still exists and may have children.
$subject = get_string('privacy:request:delete:post:subject', 'mod_forum');
$byline = '';
} else {
// The user can't see this post at all.
echo "</div>\n";
continue;
}
} else {
$by = new stdClass();
$by->name = fullname($post, $canviewfullnames);
$by->date = userdate_htmltime($post->modified);
$byline = ' ' . get_string("bynameondate", "forum", $by);
$subject = format_string($post->subject, true);
}
if ($forumtracked) {
if (!empty($post->postread)) {
$style = '<span class="forumthread read">';
} else {
$style = '<span class="forumthread unread">';
}
} else {
$style = '<span class="forumthread">';
}
echo $style;
echo "<a name='{$post->id}'></a>";
echo html_writer::link(new moodle_url('/mod/forum/discuss.php', [
'd' => $post->discussion,
'parent' => $post->id,
]), $subject);
echo $byline;
echo "</span>";
}
forum_print_posts_threaded($course, $cm, $forum, $discussion, $post, $depth-1, $reply, $forumtracked, $posts);
echo "</div>\n";
}
}
}
/**
* @todo Document this function
* @global object
* @global object
* @return void
* @deprecated since Moodle 3.7
*/
function forum_print_posts_nested($course, &$cm, $forum, $discussion, $parent, $reply, $forumtracked, $posts) {
debugging('forum_print_posts_nested() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
global $USER, $CFG;
$link = false;
if (!empty($posts[$parent->id]->children)) {
$posts = $posts[$parent->id]->children;
foreach ($posts as $post) {
echo '<div class="indent">';
if (!isloggedin()) {
$ownpost = false;
} else {
$ownpost = ($USER->id == $post->userid);
}
$post->subject = format_string($post->subject);
$postread = !empty($post->postread);
forum_print_post_start($post);
forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
'', '', $postread, true, $forumtracked);
forum_print_posts_nested($course, $cm, $forum, $discussion, $post, $reply, $forumtracked, $posts);
forum_print_post_end($post);
echo "</div>\n";
}
}
}
+19 -884
View File
@@ -509,18 +509,25 @@ function forum_user_complete($course, $user, $mod, $forum) {
if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $course->id)) {
print_error('invalidcoursemodule');
}
$context = context_module::instance($cm->id);
$discussions = forum_get_user_involved_discussions($forum->id, $user->id);
$posts = array_filter($posts, function($post) use ($discussions) {
return isset($discussions[$post->discussion]);
});
$entityfactory = mod_forum\local\container::get_entity_factory();
$rendererfactory = mod_forum\local\container::get_renderer_factory();
$postrenderer = $rendererfactory->get_posts_renderer();
foreach ($posts as $post) {
if (!isset($discussions[$post->discussion])) {
continue;
}
$discussion = $discussions[$post->discussion];
forum_print_post_start($post);
forum_print_post($post, $discussion, $forum, $cm, $course, false, false, false);
forum_print_post_end($post);
}
echo $postrenderer->render(
$USER,
[$forum->id => $entityfactory->get_forum_from_stdclass($forum, $context, $cm, $course)],
array_map(function($discussion) use ($entityfactory) {
return $entityfactory->get_discussion_from_stdclass($discussion);
}, $discussions),
array_map(function($post) use ($entityfactory) {
return $entityfactory->get_post_from_stdclass($post);
}, $posts)
);
} else {
echo "<p>".get_string("noposts", "forum")."</p>";
}
@@ -2219,611 +2226,6 @@ function forum_get_course_forum($courseid, $type) {
return $DB->get_record("forum", array("id" => "$forum->id"));
}
/**
* Return a static array of posts that are open.
*
* @return array
*/
function forum_post_nesting_cache() {
static $nesting = array();
return $nesting;
}
/**
* Return true for the first time this post was started
*
* @param int $id The id of the post to start
* @return bool
*/
function forum_should_start_post_nesting($id) {
$cache = forum_post_nesting_cache();
if (!array_key_exists($id, $cache)) {
$cache[$id] = 1;
return true;
} else {
$cache[$id]++;
return false;
}
}
/**
* Return true when all the opens are nested with a close.
*
* @param int $id The id of the post to end
* @return bool
*/
function forum_should_end_post_nesting($id) {
$cache = forum_post_nesting_cache();
if (!array_key_exists($id, $cache)) {
return true;
} else {
$cache[$id]--;
if ($cache[$id] == 0) {
unset($cache[$id]);
return true;
}
}
return false;
}
/**
* Start a forum post container
*
* @param object $post The post to print.
* @param bool $return Return the string or print it
* @return string
*/
function forum_print_post_start($post, $return = false) {
$output = '';
if (forum_should_start_post_nesting($post->id)) {
$attributes = [
'id' => 'p'.$post->id,
'tabindex' => -1,
'class' => 'relativelink'
];
$output .= html_writer::start_tag('article', $attributes);
}
if ($return) {
return $output;
}
echo $output;
return;
}
/**
* End a forum post container
*
* @param object $post The post to print.
* @param bool $return Return the string or print it
* @return string
*/
function forum_print_post_end($post, $return = false) {
$output = '';
if (forum_should_end_post_nesting($post->id)) {
$output .= html_writer::end_tag('article');
}
if ($return) {
return $output;
}
echo $output;
return;
}
/**
* Print a forum post
* This function should always be surrounded with calls to forum_print_post_start
* and forum_print_post_end to create the surrounding container for the post.
* Replies can be nested before forum_print_post_end and should reflect the structure of
* thread.
*
* @global object
* @global object
* @uses FORUM_MODE_THREADED
* @uses PORTFOLIO_FORMAT_PLAINHTML
* @uses PORTFOLIO_FORMAT_FILE
* @uses PORTFOLIO_FORMAT_RICHHTML
* @uses PORTFOLIO_ADD_TEXT_LINK
* @uses CONTEXT_MODULE
* @param object $post The post to print.
* @param object $discussion
* @param object $forum
* @param object $cm
* @param object $course
* @param boolean $ownpost Whether this post belongs to the current user.
* @param boolean $reply Whether to print a 'reply' link at the bottom of the message.
* @param boolean $link Just print a shortened version of the post as a link to the full post.
* @param string $footer Extra stuff to print after the message.
* @param string $highlight Space-separated list of terms to highlight.
* @param int $post_read true, false or -99. If we already know whether this user
* has read this post, pass that in, otherwise, pass in -99, and this
* function will work it out.
* @param boolean $dummyifcantsee When forum_user_can_see_post says that
* the current user can't see this post, if this argument is true
* (the default) then print a dummy 'you can't see this post' post.
* If false, don't output anything at all.
* @param bool|null $istracked
* @return void
*/
function forum_print_post($post, $discussion, $forum, &$cm, $course, $ownpost=false, $reply=false, $link=false,
$footer="", $highlight="", $postisread=null, $dummyifcantsee=true, $istracked=null, $return=false) {
global $USER, $CFG, $OUTPUT;
require_once($CFG->libdir . '/filelib.php');
// String cache
static $str;
// This is an extremely hacky way to ensure we only print the 'unread' anchor
// the first time we encounter an unread post on a page. Ideally this would
// be moved into the caller somehow, and be better testable. But at the time
// of dealing with this bug, this static workaround was the most surgical and
// it fits together with only printing th unread anchor id once on a given page.
static $firstunreadanchorprinted = false;
$modcontext = context_module::instance($cm->id);
$post->course = $course->id;
$post->forum = $forum->id;
$post->message = file_rewrite_pluginfile_urls($post->message, 'pluginfile.php', $modcontext->id, 'mod_forum', 'post', $post->id);
if (!empty($CFG->enableplagiarism)) {
require_once($CFG->libdir.'/plagiarismlib.php');
$post->message .= plagiarism_get_links(array('userid' => $post->userid,
'content' => $post->message,
'cmid' => $cm->id,
'course' => $post->course,
'forum' => $post->forum));
}
// caching
if (!isset($cm->cache)) {
$cm->cache = new stdClass;
}
if (!isset($cm->cache->caps)) {
$cm->cache->caps = array();
$cm->cache->caps['mod/forum:viewdiscussion'] = has_capability('mod/forum:viewdiscussion', $modcontext);
$cm->cache->caps['moodle/site:viewfullnames'] = has_capability('moodle/site:viewfullnames', $modcontext);
$cm->cache->caps['mod/forum:editanypost'] = has_capability('mod/forum:editanypost', $modcontext);
$cm->cache->caps['mod/forum:splitdiscussions'] = has_capability('mod/forum:splitdiscussions', $modcontext);
$cm->cache->caps['mod/forum:deleteownpost'] = has_capability('mod/forum:deleteownpost', $modcontext);
$cm->cache->caps['mod/forum:deleteanypost'] = has_capability('mod/forum:deleteanypost', $modcontext);
$cm->cache->caps['mod/forum:viewanyrating'] = has_capability('mod/forum:viewanyrating', $modcontext);
$cm->cache->caps['mod/forum:exportpost'] = has_capability('mod/forum:exportpost', $modcontext);
$cm->cache->caps['mod/forum:exportownpost'] = has_capability('mod/forum:exportownpost', $modcontext);
}
if (!isset($cm->uservisible)) {
$cm->uservisible = \core_availability\info_module::is_user_visible($cm, 0, false);
}
if ($istracked && is_null($postisread)) {
$postisread = forum_tp_is_post_read($USER->id, $post);
}
if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm, false)) {
// Do _not_ check the deleted flag - we need to display a different UI.
$output = '';
if (!$dummyifcantsee) {
if ($return) {
return $output;
}
echo $output;
return;
}
$output .= html_writer::start_tag('div', array('class' => 'forumpost clearfix',
'aria-label' => get_string('hiddenforumpost', 'forum')));
$output .= html_writer::start_tag('header', array('class' => 'row header'));
$output .= html_writer::tag('div', '', array('class' => 'left picture', 'role' => 'presentation')); // Picture.
if ($post->parent) {
$output .= html_writer::start_tag('div', array('class' => 'topic'));
} else {
$output .= html_writer::start_tag('div', array('class' => 'topic starter'));
}
$output .= html_writer::tag('div', get_string('forumsubjecthidden','forum'), array('class' => 'subject',
'role' => 'header',
'id' => ('headp' . $post->id))); // Subject.
$authorclasses = array('class' => 'author');
$output .= html_writer::tag('address', get_string('forumauthorhidden', 'forum'), $authorclasses); // Author.
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('header'); // Header.
$output .= html_writer::start_tag('div', array('class'=>'row'));
$output .= html_writer::tag('div', '&nbsp;', array('class'=>'left side')); // Groups
$output .= html_writer::tag('div', get_string('forumbodyhidden','forum'), array('class'=>'content')); // Content
$output .= html_writer::end_tag('div'); // row
$output .= html_writer::end_tag('div'); // forumpost
if ($return) {
return $output;
}
echo $output;
return;
}
if (!empty($post->deleted)) {
// Note: Posts marked as deleted are still returned by the above forum_user_can_post because it is required for
// nesting of posts.
$output = '';
if (!$dummyifcantsee) {
if ($return) {
return $output;
}
echo $output;
return;
}
$output .= html_writer::start_tag('div', [
'class' => 'forumpost clearfix',
'aria-label' => get_string('forumbodydeleted', 'forum'),
]);
$output .= html_writer::start_tag('header', array('class' => 'row header'));
$output .= html_writer::tag('div', '', array('class' => 'left picture', 'role' => 'presentation'));
$classes = ['topic'];
if (!empty($post->parent)) {
$classes[] = 'starter';
}
$output .= html_writer::start_tag('div', ['class' => implode(' ', $classes)]);
// Subject.
$output .= html_writer::tag('div', get_string('forumsubjectdeleted', 'forum'), [
'class' => 'subject',
'role' => 'header',
'id' => ('headp' . $post->id)
]);
// Author.
$output .= html_writer::tag('address', '', ['class' => 'author']);
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('header'); // End header.
$output .= html_writer::start_tag('div', ['class' => 'row']);
$output .= html_writer::tag('div', '&nbsp;', ['class' => 'left side']); // Groups.
$output .= html_writer::tag('div', get_string('forumbodydeleted', 'forum'), ['class' => 'content']); // Content.
$output .= html_writer::end_tag('div'); // End row.
$output .= html_writer::end_tag('div'); // End forumpost.
if ($return) {
return $output;
}
echo $output;
return;
}
if (empty($str)) {
$str = new stdClass;
$str->edit = get_string('edit', 'forum');
$str->delete = get_string('delete', 'forum');
$str->reply = get_string('reply', 'forum');
$str->parent = get_string('parent', 'forum');
$str->pruneheading = get_string('pruneheading', 'forum');
$str->prune = get_string('prune', 'forum');
$str->displaymode = get_user_preferences('forum_displaymode', $CFG->forum_displaymode);
$str->markread = get_string('markread', 'forum');
$str->markunread = get_string('markunread', 'forum');
}
$discussionlink = new moodle_url('/mod/forum/discuss.php', array('d'=>$post->discussion));
// Build an object that represents the posting user
$postuser = new stdClass;
$postuserfields = explode(',', user_picture::fields());
$postuser = username_load_fields_from_object($postuser, $post, null, $postuserfields);
$postuser->id = $post->userid;
$postuser->fullname = fullname($postuser, $cm->cache->caps['moodle/site:viewfullnames']);
$postuser->profilelink = new moodle_url('/user/view.php', array('id'=>$post->userid, 'course'=>$course->id));
// Prepare the groups the posting user belongs to
if (isset($cm->cache->usersgroups)) {
$groups = array();
if (isset($cm->cache->usersgroups[$post->userid])) {
foreach ($cm->cache->usersgroups[$post->userid] as $gid) {
$groups[$gid] = $cm->cache->groups[$gid];
}
}
} else {
$groups = groups_get_all_groups($course->id, $post->userid, $cm->groupingid);
}
// Prepare the attachements for the post, files then images
list($attachments, $attachedimages) = forum_print_attachments($post, $cm, 'separateimages');
// Determine if we need to shorten this post
$shortenpost = ($link && (strlen(strip_tags($post->message)) > $CFG->forum_longpost));
// Prepare an array of commands
$commands = array();
// Add a permalink.
$permalink = new moodle_url($discussionlink);
$permalink->set_anchor('p' . $post->id);
$commands[] = array('url' => $permalink, 'text' => get_string('permalink', 'forum'), 'attributes' => ['rel' => 'bookmark']);
// SPECIAL CASE: The front page can display a news item post to non-logged in users.
// Don't display the mark read / unread controls in this case.
if ($istracked && $CFG->forum_usermarksread && isloggedin()) {
$url = new moodle_url($discussionlink, array('postid'=>$post->id, 'mark'=>'unread'));
$text = $str->markunread;
if (!$postisread) {
$url->param('mark', 'read');
$text = $str->markread;
}
if ($str->displaymode == FORUM_MODE_THREADED) {
$url->param('parent', $post->parent);
} else {
$url->set_anchor('p'.$post->id);
}
$commands[] = array('url'=>$url, 'text'=>$text, 'attributes' => ['rel' => 'bookmark']);
}
// Zoom in to the parent specifically
if ($post->parent) {
$url = new moodle_url($discussionlink);
if ($str->displaymode == FORUM_MODE_THREADED) {
$url->param('parent', $post->parent);
} else {
$url->set_anchor('p'.$post->parent);
}
$commands[] = array('url'=>$url, 'text'=>$str->parent, 'attributes' => ['rel' => 'bookmark']);
}
// Hack for allow to edit news posts those are not displayed yet until they are displayed
$age = time() - $post->created;
if (!$post->parent && $forum->type == 'news' && $discussion->timestart > time()) {
$age = 0;
}
if ($forum->type == 'single' and $discussion->firstpost == $post->id) {
if (has_capability('moodle/course:manageactivities', $modcontext)) {
// The first post in single simple is the forum description.
$commands[] = array('url'=>new moodle_url('/course/modedit.php', array('update'=>$cm->id, 'sesskey'=>sesskey(), 'return'=>1)), 'text'=>$str->edit);
}
} else if (($ownpost && $age < $CFG->maxeditingtime) || $cm->cache->caps['mod/forum:editanypost']) {
$commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('edit'=>$post->id)), 'text'=>$str->edit);
}
if ($cm->cache->caps['mod/forum:splitdiscussions'] && $post->parent && $forum->type != 'single') {
$commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('prune'=>$post->id)), 'text'=>$str->prune, 'title'=>$str->pruneheading);
}
if ($forum->type == 'single' and $discussion->firstpost == $post->id) {
// Do not allow deleting of first post in single simple type.
} else if (($ownpost && $age < $CFG->maxeditingtime && $cm->cache->caps['mod/forum:deleteownpost']) || $cm->cache->caps['mod/forum:deleteanypost']) {
$commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('delete'=>$post->id)), 'text'=>$str->delete);
}
if ($reply) {
$commands[] = array('url'=>new moodle_url('/mod/forum/post.php#mformforum', array('reply'=>$post->id)), 'text'=>$str->reply);
}
if ($CFG->enableportfolios && ($cm->cache->caps['mod/forum:exportpost'] || ($ownpost && $cm->cache->caps['mod/forum:exportownpost']))) {
$p = array('postid' => $post->id);
require_once($CFG->libdir.'/portfoliolib.php');
$button = new portfolio_add_button();
$button->set_callback_options('forum_portfolio_caller', array('postid' => $post->id), 'mod_forum');
if (empty($attachments)) {
$button->set_formats(PORTFOLIO_FORMAT_PLAINHTML);
} else {
$button->set_formats(PORTFOLIO_FORMAT_RICHHTML);
}
$porfoliohtml = $button->to_html(PORTFOLIO_ADD_TEXT_LINK);
if (!empty($porfoliohtml)) {
$commands[] = $porfoliohtml;
}
}
// Finished building commands
// Begin output
$output = '';
if ($istracked) {
if ($postisread) {
$forumpostclass = ' read';
} else {
$forumpostclass = ' unread';
// If this is the first unread post printed then give it an anchor and id of unread.
if (!$firstunreadanchorprinted) {
$output .= html_writer::tag('a', '', array('id' => 'unread'));
$firstunreadanchorprinted = true;
}
}
} else {
// ignore trackign status if not tracked or tracked param missing
$forumpostclass = '';
}
$topicclass = '';
if (empty($post->parent)) {
$topicclass = ' firstpost starter';
}
if (!empty($post->lastpost)) {
$forumpostclass .= ' lastpost';
}
// Flag to indicate whether we should hide the author or not.
$authorhidden = forum_is_author_hidden($post, $forum);
$postbyuser = new stdClass;
$postbyuser->post = $post->subject;
$postbyuser->user = $postuser->fullname;
$discussionbyuser = get_string('postbyuser', 'forum', $postbyuser);
// Begin forum post.
$output .= html_writer::start_div('forumpost clearfix' . $forumpostclass . $topicclass,
['aria-label' => $discussionbyuser]);
// Begin header row.
$output .= html_writer::start_tag('header', ['class' => 'row header clearfix']);
// User picture.
if (!$authorhidden) {
$picture = $OUTPUT->user_picture($postuser, ['courseid' => $course->id]);
$output .= html_writer::div($picture, 'left picture', ['role' => 'presentation']);
$topicclass = 'topic' . $topicclass;
}
// Begin topic column.
$output .= html_writer::start_div($topicclass);
$postsubject = $post->subject;
if (empty($post->subjectnoformat)) {
$postsubject = format_string($postsubject);
}
$output .= html_writer::div($postsubject, 'subject', ['role' => 'heading', 'aria-level' => '1', 'id' => ('headp' . $post->id)]);
if ($authorhidden) {
$bytext = userdate_htmltime($post->created);
} else {
$by = new stdClass();
$by->date = userdate_htmltime($post->created);
$by->name = html_writer::link($postuser->profilelink, $postuser->fullname);
$bytext = get_string('bynameondate', 'forum', $by);
}
$bytextoptions = [
'class' => 'author'
];
$output .= html_writer::tag('address', $bytext, $bytextoptions);
// End topic column.
$output .= html_writer::end_div();
// End header row.
$output .= html_writer::end_tag('header');
// Row with the forum post content.
$output .= html_writer::start_div('row maincontent clearfix');
// Show if author is not hidden or we have groups.
if (!$authorhidden || $groups) {
$output .= html_writer::start_div('left');
$groupoutput = '';
if ($groups) {
$groupoutput = print_group_picture($groups, $course->id, false, true, true);
}
if (empty($groupoutput)) {
$groupoutput = '&nbsp;';
}
$output .= html_writer::div($groupoutput, 'grouppictures');
$output .= html_writer::end_div(); // Left side.
}
$output .= html_writer::start_tag('div', array('class'=>'no-overflow'));
$output .= html_writer::start_tag('div', array('class'=>'content'));
$options = new stdClass;
$options->para = false;
$options->trusted = $post->messagetrust;
$options->context = $modcontext;
if ($shortenpost) {
// Prepare shortened version by filtering the text then shortening it.
$postclass = 'shortenedpost';
$postcontent = format_text($post->message, $post->messageformat, $options);
$postcontent = shorten_text($postcontent, $CFG->forum_shortpost);
$postcontent .= html_writer::link($discussionlink, get_string('readtherest', 'forum'));
$postcontent .= html_writer::tag('div', '('.get_string('numwords', 'moodle', count_words($post->message)).')',
array('class'=>'post-word-count'));
} else {
// Prepare whole post
$postclass = 'fullpost';
$postcontent = format_text($post->message, $post->messageformat, $options, $course->id);
if (!empty($highlight)) {
$postcontent = highlight($highlight, $postcontent);
}
if (!empty($forum->displaywordcount)) {
$postcontent .= html_writer::tag('div', get_string('numwords', 'moodle', count_words($postcontent)),
array('class'=>'post-word-count'));
}
$postcontent .= html_writer::tag('div', $attachedimages, array('class'=>'attachedimages'));
}
if (\core_tag_tag::is_enabled('mod_forum', 'forum_posts')) {
$postcontent .= $OUTPUT->tag_list(core_tag_tag::get_item_tags('mod_forum', 'forum_posts', $post->id), null, 'forum-tags');
}
// Output the post content
$output .= html_writer::tag('div', $postcontent, array('class'=>'posting '.$postclass));
$output .= html_writer::end_tag('div'); // Content
$output .= html_writer::end_tag('div'); // Content mask
$output .= html_writer::end_tag('div'); // Row
$output .= html_writer::start_tag('nav', array('class' => 'row side'));
$output .= html_writer::tag('div','&nbsp;', array('class'=>'left'));
$output .= html_writer::start_tag('div', array('class'=>'options clearfix'));
if (!empty($attachments)) {
$output .= html_writer::tag('div', $attachments, array('class' => 'attachments'));
}
// Output ratings
if (!empty($post->rating)) {
$output .= html_writer::tag('div', $OUTPUT->render($post->rating), array('class'=>'forum-post-rating'));
}
// Output the commands
$commandhtml = array();
foreach ($commands as $command) {
if (is_array($command)) {
$attributes = ['class' => 'nav-item nav-link'];
if (isset($command['attributes'])) {
$attributes = array_merge($attributes, $command['attributes']);
}
$commandhtml[] = html_writer::link($command['url'], $command['text'], $attributes);
} else {
$commandhtml[] = $command;
}
}
$output .= html_writer::tag('div', implode(' ', $commandhtml), array('class' => 'commands nav'));
// Output link to post if required
if ($link) {
if (forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext)) {
$langstring = 'discussthistopic';
} else {
$langstring = 'viewthediscussion';
}
if ($post->replies == 1) {
$replystring = get_string('repliesone', 'forum', $post->replies);
} else {
$replystring = get_string('repliesmany', 'forum', $post->replies);
}
if (!empty($discussion->unread) && $discussion->unread !== '-') {
$replystring .= ' <span class="sep">/</span> <span class="unread">';
$unreadlink = new moodle_url($discussionlink, null, 'unread');
if ($discussion->unread == 1) {
$replystring .= html_writer::link($unreadlink, get_string('unreadpostsone', 'forum'));
} else {
$replystring .= html_writer::link($unreadlink, get_string('unreadpostsnumber', 'forum', $discussion->unread));
}
$replystring .= '</span>';
}
$output .= html_writer::start_tag('div', array('class'=>'link'));
$output .= html_writer::link($discussionlink, get_string($langstring, 'forum'));
$output .= '&nbsp;('.$replystring.')';
$output .= html_writer::end_tag('div'); // link
}
// Output footer if required
if ($footer) {
$output .= html_writer::tag('div', $footer, array('class'=>'footer'));
}
// Close remaining open divs
$output .= html_writer::end_tag('div'); // content
$output .= html_writer::end_tag('nav'); // row
$output .= html_writer::end_tag('div'); // forumpost
// Mark the forum post as read if required
if ($istracked && !$CFG->forum_usermarksread && !$postisread) {
forum_tp_mark_post_read($USER->id, $post);
}
if ($return) {
return $output;
}
echo $output;
return;
}
/**
* Return rating related permissions
*
@@ -3111,8 +2513,8 @@ function forum_print_discussion_header(&$post, $forum, $group = -1, $datestring
echo $post->unread;
echo '</a>';
echo '<a title="'.$strmarkalldread.'" href="'.$CFG->wwwroot.'/mod/forum/markposts.php?f='.
$forum->id.'&amp;d='.$post->discussion.'&amp;mark=read&amp;return=/mod/forum/view.php&amp;sesskey=' . sesskey() . '">' .
$OUTPUT->pix_icon('t/markasread', $strmarkalldread) . '</a>';
$forum->id.'&amp;d='.$post->discussion.'&amp;mark=read&amp;return=/mod/forum/view.php&amp;sesskey=' .
sesskey() . '">' . $OUTPUT->pix_icon('t/markasread', $strmarkalldread) . '</a>';
echo '</span>';
} else {
echo '<span class="read">';
@@ -4928,273 +4330,6 @@ function forum_print_latest_discussions($course, $forum, $maxdiscussions = -1, $
}
}
/**
* Prints a forum discussion
*
* @uses CONTEXT_MODULE
* @uses FORUM_MODE_FLATNEWEST
* @uses FORUM_MODE_FLATOLDEST
* @uses FORUM_MODE_THREADED
* @uses FORUM_MODE_NESTED
* @param stdClass $course
* @param stdClass $cm
* @param stdClass $forum
* @param stdClass $discussion
* @param stdClass $post
* @param int $mode
* @param mixed $canreply
* @param bool $canrate
*/
function forum_print_discussion($course, $cm, $forum, $discussion, $post, $mode, $canreply=NULL, $canrate=false) {
global $USER, $CFG;
require_once($CFG->dirroot.'/rating/lib.php');
$ownpost = (isloggedin() && $USER->id == $post->userid);
$modcontext = context_module::instance($cm->id);
if ($canreply === NULL) {
$reply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext);
} else {
$reply = $canreply;
}
// $cm holds general cache for forum functions
$cm->cache = new stdClass;
$cm->cache->groups = groups_get_all_groups($course->id, 0, $cm->groupingid);
$cm->cache->usersgroups = array();
$posters = array();
// preload all posts - TODO: improve...
if ($mode == FORUM_MODE_FLATNEWEST) {
$sort = "p.created DESC";
} else {
$sort = "p.created ASC";
}
$forumtracked = forum_tp_is_tracked($forum);
$posts = forum_get_all_discussion_posts($discussion->id, $sort, $forumtracked);
$post = $posts[$post->id];
foreach ($posts as $pid=>$p) {
$posters[$p->userid] = $p->userid;
}
// preload all groups of ppl that posted in this discussion
if ($postersgroups = groups_get_all_groups($course->id, $posters, $cm->groupingid, 'gm.id, gm.groupid, gm.userid')) {
foreach($postersgroups as $pg) {
if (!isset($cm->cache->usersgroups[$pg->userid])) {
$cm->cache->usersgroups[$pg->userid] = array();
}
$cm->cache->usersgroups[$pg->userid][$pg->groupid] = $pg->groupid;
}
unset($postersgroups);
}
//load ratings
if ($forum->assessed != RATING_AGGREGATE_NONE) {
$ratingoptions = new stdClass;
$ratingoptions->context = $modcontext;
$ratingoptions->component = 'mod_forum';
$ratingoptions->ratingarea = 'post';
$ratingoptions->items = $posts;
$ratingoptions->aggregate = $forum->assessed;//the aggregation method
$ratingoptions->scaleid = $forum->scale;
$ratingoptions->userid = $USER->id;
if ($forum->type == 'single' or !$discussion->id) {
$ratingoptions->returnurl = "$CFG->wwwroot/mod/forum/view.php?id=$cm->id";
} else {
$ratingoptions->returnurl = "$CFG->wwwroot/mod/forum/discuss.php?d=$discussion->id";
}
$ratingoptions->assesstimestart = $forum->assesstimestart;
$ratingoptions->assesstimefinish = $forum->assesstimefinish;
$rm = new rating_manager();
$posts = $rm->get_ratings($ratingoptions);
}
$post->forum = $forum->id; // Add the forum id to the post object, later used by forum_print_post
$post->forumtype = $forum->type;
$post->subject = format_string($post->subject);
$postread = !empty($post->postread);
forum_print_post_start($post);
forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, false,
'', '', $postread, true, $forumtracked);
switch ($mode) {
case FORUM_MODE_FLATOLDEST :
case FORUM_MODE_FLATNEWEST :
default:
forum_print_posts_flat($course, $cm, $forum, $discussion, $post, $mode, $reply, $forumtracked, $posts);
break;
case FORUM_MODE_THREADED :
forum_print_posts_threaded($course, $cm, $forum, $discussion, $post, 0, $reply, $forumtracked, $posts);
break;
case FORUM_MODE_NESTED :
forum_print_posts_nested($course, $cm, $forum, $discussion, $post, $reply, $forumtracked, $posts);
break;
}
forum_print_post_end($post);
}
/**
* @global object
* @global object
* @uses FORUM_MODE_FLATNEWEST
* @param object $course
* @param object $cm
* @param object $forum
* @param object $discussion
* @param object $post
* @param object $mode
* @param bool $reply
* @param bool $forumtracked
* @param array $posts
* @return void
*/
function forum_print_posts_flat($course, &$cm, $forum, $discussion, $post, $mode, $reply, $forumtracked, $posts) {
global $USER, $CFG;
$link = false;
foreach ($posts as $post) {
if (!$post->parent) {
continue;
}
$post->subject = format_string($post->subject);
$ownpost = ($USER->id == $post->userid);
$postread = !empty($post->postread);
forum_print_post_start($post);
forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
'', '', $postread, true, $forumtracked);
forum_print_post_end($post);
}
}
/**
* @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_start($post);
forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
'', '', $postread, true, $forumtracked);
forum_print_post_end($post);
} else {
if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm, true)) {
if (forum_user_can_see_post($forum, $discussion, $post, null, $cm, false)) {
// This post has been deleted but still exists and may have children.
$subject = get_string('privacy:request:delete:post:subject', 'mod_forum');
$byline = '';
} else {
// The user can't see this post at all.
echo "</div>\n";
continue;
}
} else {
$by = new stdClass();
$by->name = fullname($post, $canviewfullnames);
$by->date = userdate_htmltime($post->modified);
$byline = ' ' . get_string("bynameondate", "forum", $by);
$subject = format_string($post->subject, true);
}
if ($forumtracked) {
if (!empty($post->postread)) {
$style = '<span class="forumthread read">';
} else {
$style = '<span class="forumthread unread">';
}
} else {
$style = '<span class="forumthread">';
}
echo $style;
echo "<a name='{$post->id}'></a>";
echo html_writer::link(new moodle_url('/mod/forum/discuss.php', [
'd' => $post->discussion,
'parent' => $post->id,
]), $subject);
echo $byline;
echo "</span>";
}
forum_print_posts_threaded($course, $cm, $forum, $discussion, $post, $depth-1, $reply, $forumtracked, $posts);
echo "</div>\n";
}
}
}
/**
* @todo Document this function
* @global object
* @global object
* @return void
*/
function forum_print_posts_nested($course, &$cm, $forum, $discussion, $parent, $reply, $forumtracked, $posts) {
global $USER, $CFG;
$link = false;
if (!empty($posts[$parent->id]->children)) {
$posts = $posts[$parent->id]->children;
foreach ($posts as $post) {
echo '<div class="indent">';
if (!isloggedin()) {
$ownpost = false;
} else {
$ownpost = ($USER->id == $post->userid);
}
$post->subject = format_string($post->subject);
$postread = !empty($post->postread);
forum_print_post_start($post);
forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
'', '', $postread, true, $forumtracked);
forum_print_posts_nested($course, $cm, $forum, $discussion, $post, $reply, $forumtracked, $posts);
forum_print_post_end($post);
echo "</div>\n";
}
}
}
/**
* Returns all forum posts since a given time in specified forum.
*