ad61a8a2e0a0954e5dce965c4d9c61ee89082f10
[moodle.git] / mod / forum / deprecatedlib.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * @package   mod_forum
19  * @copyright 2014 Andrew Robert Nicols <andrew@nicols.co.uk>
20  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
21  */
23 defined('MOODLE_INTERNAL') || die();
25 // Deprecated a very long time ago.
27 /**
28  * @deprecated since Moodle 1.1 - please do not use this function any more.
29  */
30 function forum_count_unrated_posts() {
31     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
32 }
35 // Since Moodle 1.5.
37 /**
38  * @deprecated since Moodle 1.5 - please do not use this function any more.
39  */
40 function forum_tp_count_discussion_read_records() {
41     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
42 }
44 /**
45  * @deprecated since Moodle 1.5 - please do not use this function any more.
46  */
47 function forum_get_user_discussions() {
48     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
49 }
52 // Since Moodle 1.6.
54 /**
55  * @deprecated since Moodle 1.6 - please do not use this function any more.
56  */
57 function forum_tp_count_forum_posts() {
58     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
59 }
61 /**
62  * @deprecated since Moodle 1.6 - please do not use this function any more.
63  */
64 function forum_tp_count_forum_read_records() {
65     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
66 }
69 // Since Moodle 1.7.
71 /**
72  * @deprecated since Moodle 1.7 - please do not use this function any more.
73  */
74 function forum_get_open_modes() {
75     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
76 }
79 // Since Moodle 1.9.
81 /**
82  * @deprecated since Moodle 1.9 MDL-13303 - please do not use this function any more.
83  */
84 function forum_get_child_posts() {
85     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
86 }
88 /**
89  * @deprecated since Moodle 1.9 MDL-13303 - please do not use this function any more.
90  */
91 function forum_get_discussion_posts() {
92     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
93 }
96 // Since Moodle 2.0.
98 /**
99  * @deprecated since Moodle 2.0 MDL-21657 - please do not use this function any more.
100  */
101 function forum_get_ratings() {
102     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
105 /**
106  * @deprecated since Moodle 2.0 MDL-14632 - please do not use this function any more.
107  */
108 function forum_get_tracking_link() {
109     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
112 /**
113  * @deprecated since Moodle 2.0 MDL-14113 - please do not use this function any more.
114  */
115 function forum_tp_count_discussion_unread_posts() {
116     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
119 /**
120  * @deprecated since Moodle 2.0 MDL-23479 - please do not use this function any more.
121  */
122 function forum_convert_to_roles() {
123     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
126 /**
127  * @deprecated since Moodle 2.0 MDL-14113 - please do not use this function any more.
128  */
129 function forum_tp_get_read_records() {
130     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
133 /**
134  * @deprecated since Moodle 2.0 MDL-14113 - please do not use this function any more.
135  */
136 function forum_tp_get_discussion_read_records() {
137     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
140 // Deprecated in 2.3.
142 /**
143  * @deprecated since Moodle 2.3 MDL-33166 - please do not use this function any more.
144  */
145 function forum_user_enrolled() {
146     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
150 // Deprecated in 2.4.
152 /**
153  * @deprecated since Moodle 2.4 use forum_user_can_see_post() instead
154  */
155 function forum_user_can_view_post() {
156     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
160 // Deprecated in 2.6.
162 /**
163  * FORUM_TRACKING_ON - deprecated alias for FORUM_TRACKING_FORCED.
164  * @deprecated since 2.6
165  */
166 define('FORUM_TRACKING_ON', 2);
168 /**
169  * @deprecated since Moodle 2.6
170  * @see shorten_text()
171  */
172 function forum_shorten_post($message) {
173     throw new coding_exception(__FUNCTION__ . '() can not be used any more. '
174         . 'Please use shorten_text($message, $CFG->forum_shortpost) instead.');
177 // Deprecated in 2.8.
179 /**
180  * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::is_subscribed() instead
181  */
182 function forum_is_subscribed() {
183     throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
186 /**
187  * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::subscribe_user() instead
188  */
189 function forum_subscribe() {
190     throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
191         . \mod_forum\subscriptions::class . '::subscribe_user() instead');
194 /**
195  * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::unsubscribe_user() instead
196  */
197 function forum_unsubscribe() {
198     throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
199         . \mod_forum\subscriptions::class . '::unsubscribe_user() instead');
202 /**
203  * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::fetch_subscribed_users() instead
204   */
205 function forum_subscribed_users() {
206     throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
207         . \mod_forum\subscriptions::class . '::fetch_subscribed_users() instead');
210 /**
211  * Determine whether the forum is force subscribed.
212  *
213  * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::is_forcesubscribed() instead
214  */
215 function forum_is_forcesubscribed($forum) {
216     throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
217         . \mod_forum\subscriptions::class . '::is_forcesubscribed() instead');
220 /**
221  * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::set_subscription_mode() instead
222  */
223 function forum_forcesubscribe($forumid, $value = 1) {
224     throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
225         . \mod_forum\subscriptions::class . '::set_subscription_mode() instead');
228 /**
229  * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::get_subscription_mode() instead
230  */
231 function forum_get_forcesubscribed($forum) {
232     throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
233         . \mod_forum\subscriptions::class . '::set_subscription_mode() instead');
236 /**
237  * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::is_subscribed in combination wtih
238  * \mod_forum\subscriptions::fill_subscription_cache_for_course instead.
239  */
240 function forum_get_subscribed_forums() {
241     throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
242         . \mod_forum\subscriptions::class . '::is_subscribed(), and '
243         . \mod_forum\subscriptions::class . '::fill_subscription_cache_for_course() instead');
246 /**
247  * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::get_unsubscribable_forums() instead
248  */
249 function forum_get_optional_subscribed_forums() {
250     throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
251         . \mod_forum\subscriptions::class . '::get_unsubscribable_forums() instead');
254 /**
255  * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::get_potential_subscribers() instead
256  */
257 function forum_get_potential_subscribers() {
258     throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
259         . \mod_forum\subscriptions::class . '::get_potential_subscribers() instead');
262 /**
263  * Builds and returns the body of the email notification in plain text.
264  *
265  * @uses CONTEXT_MODULE
266  * @param object $course
267  * @param object $cm
268  * @param object $forum
269  * @param object $discussion
270  * @param object $post
271  * @param object $userfrom
272  * @param object $userto
273  * @param boolean $bare
274  * @param string $replyaddress The inbound address that a user can reply to the generated e-mail with. [Since 2.8].
275  * @return string The email body in plain text format.
276  * @deprecated since Moodle 3.0 use \mod_forum\output\forum_post_email instead
277  */
278 function forum_make_mail_text($course, $cm, $forum, $discussion, $post, $userfrom, $userto, $bare = false, $replyaddress = null) {
279     global $PAGE;
280     $renderable = new \mod_forum\output\forum_post_email(
281         $course,
282         $cm,
283         $forum,
284         $discussion,
285         $post,
286         $userfrom,
287         $userto,
288         forum_user_can_post($forum, $discussion, $userto, $cm, $course)
289         );
291     $modcontext = context_module::instance($cm->id);
292     $renderable->viewfullnames = has_capability('moodle/site:viewfullnames', $modcontext, $userto->id);
294     if ($bare) {
295         $renderer = $PAGE->get_renderer('mod_forum', 'emaildigestfull', 'textemail');
296     } else {
297         $renderer = $PAGE->get_renderer('mod_forum', 'email', 'textemail');
298     }
300     debugging("forum_make_mail_text() has been deprecated, please use the \mod_forum\output\forum_post_email renderable instead.",
301             DEBUG_DEVELOPER);
303     return $renderer->render($renderable);
306 /**
307  * Builds and returns the body of the email notification in html format.
308  *
309  * @param object $course
310  * @param object $cm
311  * @param object $forum
312  * @param object $discussion
313  * @param object $post
314  * @param object $userfrom
315  * @param object $userto
316  * @param string $replyaddress The inbound address that a user can reply to the generated e-mail with. [Since 2.8].
317  * @return string The email text in HTML format
318  * @deprecated since Moodle 3.0 use \mod_forum\output\forum_post_email instead
319  */
320 function forum_make_mail_html($course, $cm, $forum, $discussion, $post, $userfrom, $userto, $replyaddress = null) {
321     return forum_make_mail_post($course,
322         $cm,
323         $forum,
324         $discussion,
325         $post,
326         $userfrom,
327         $userto,
328         forum_user_can_post($forum, $discussion, $userto, $cm, $course)
329     );
332 /**
333  * Given the data about a posting, builds up the HTML to display it and
334  * returns the HTML in a string.  This is designed for sending via HTML email.
335  *
336  * @param object $course
337  * @param object $cm
338  * @param object $forum
339  * @param object $discussion
340  * @param object $post
341  * @param object $userfrom
342  * @param object $userto
343  * @param bool $ownpost
344  * @param bool $reply
345  * @param bool $link
346  * @param bool $rate
347  * @param string $footer
348  * @return string
349  * @deprecated since Moodle 3.0 use \mod_forum\output\forum_post_email instead
350  */
351 function forum_make_mail_post($course, $cm, $forum, $discussion, $post, $userfrom, $userto,
352                               $ownpost=false, $reply=false, $link=false, $rate=false, $footer="") {
353     global $PAGE;
354     $renderable = new \mod_forum\output\forum_post_email(
355         $course,
356         $cm,
357         $forum,
358         $discussion,
359         $post,
360         $userfrom,
361         $userto,
362         $reply);
364     $modcontext = context_module::instance($cm->id);
365     $renderable->viewfullnames = has_capability('moodle/site:viewfullnames', $modcontext, $userto->id);
367     // Assume that this is being used as a standard forum email.
368     $renderer = $PAGE->get_renderer('mod_forum', 'email', 'htmlemail');
370     debugging("forum_make_mail_post() has been deprecated, please use the \mod_forum\output\forum_post_email renderable instead.",
371             DEBUG_DEVELOPER);
373     return $renderer->render($renderable);
376 /**
377  * Removes properties from user record that are not necessary for sending post notifications.
378  *
379  * @param stdClass $user
380  * @return void, $user parameter is modified
381  * @deprecated since Moodle 3.7
382  */
383 function forum_cron_minimise_user_record(stdClass $user) {
384     debugging("forum_cron_minimise_user_record() has been deprecated and has not been replaced.",
385             DEBUG_DEVELOPER);
387     // We store large amount of users in one huge array,
388     // make sure we do not store info there we do not actually need
389     // in mail generation code or messaging.
391     unset($user->institution);
392     unset($user->department);
393     unset($user->address);
394     unset($user->city);
395     unset($user->url);
396     unset($user->currentlogin);
397     unset($user->description);
398     unset($user->descriptionformat);
401 /**
402  * Function to be run periodically according to the scheduled task.
403  *
404  * Finds all posts that have yet to be mailed out, and mails them out to all subscribers as well as other maintance
405  * tasks.
406  *
407  * @deprecated since Moodle 3.7
408  */
409 function forum_cron() {
410     debugging("forum_cron() has been deprecated and replaced with new tasks. Please uses these instead.",
411             DEBUG_DEVELOPER);
414 /**
415  * Prints a forum discussion
416  *
417  * @uses CONTEXT_MODULE
418  * @uses FORUM_MODE_FLATNEWEST
419  * @uses FORUM_MODE_FLATOLDEST
420  * @uses FORUM_MODE_THREADED
421  * @uses FORUM_MODE_NESTED
422  * @param stdClass $course
423  * @param stdClass $cm
424  * @param stdClass $forum
425  * @param stdClass $discussion
426  * @param stdClass $post
427  * @param int $mode
428  * @param mixed $canreply
429  * @param bool $canrate
430  * @deprecated since Moodle 3.7
431  */
432 function forum_print_discussion($course, $cm, $forum, $discussion, $post, $mode, $canreply=NULL, $canrate=false) {
433     debugging('forum_print_discussion() has been deprecated, please use \mod_forum\local\renderers\discussion instead.', DEBUG_DEVELOPER);
435     global $USER, $CFG;
437     require_once($CFG->dirroot.'/rating/lib.php');
439     $ownpost = (isloggedin() && $USER->id == $post->userid);
441     $modcontext = context_module::instance($cm->id);
442     if ($canreply === NULL) {
443         $reply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext);
444     } else {
445         $reply = $canreply;
446     }
448     // $cm holds general cache for forum functions
449     $cm->cache = new stdClass;
450     $cm->cache->groups      = groups_get_all_groups($course->id, 0, $cm->groupingid);
451     $cm->cache->usersgroups = array();
453     $posters = array();
455     // preload all posts - TODO: improve...
456     if ($mode == FORUM_MODE_FLATNEWEST) {
457         $sort = "p.created DESC";
458     } else {
459         $sort = "p.created ASC";
460     }
462     $forumtracked = forum_tp_is_tracked($forum);
463     $posts = forum_get_all_discussion_posts($discussion->id, $sort, $forumtracked);
464     $post = $posts[$post->id];
466     foreach ($posts as $pid=>$p) {
467         $posters[$p->userid] = $p->userid;
468     }
470     // preload all groups of ppl that posted in this discussion
471     if ($postersgroups = groups_get_all_groups($course->id, $posters, $cm->groupingid, 'gm.id, gm.groupid, gm.userid')) {
472         foreach($postersgroups as $pg) {
473             if (!isset($cm->cache->usersgroups[$pg->userid])) {
474                 $cm->cache->usersgroups[$pg->userid] = array();
475             }
476             $cm->cache->usersgroups[$pg->userid][$pg->groupid] = $pg->groupid;
477         }
478         unset($postersgroups);
479     }
481     //load ratings
482     if ($forum->assessed != RATING_AGGREGATE_NONE) {
483         $ratingoptions = new stdClass;
484         $ratingoptions->context = $modcontext;
485         $ratingoptions->component = 'mod_forum';
486         $ratingoptions->ratingarea = 'post';
487         $ratingoptions->items = $posts;
488         $ratingoptions->aggregate = $forum->assessed;//the aggregation method
489         $ratingoptions->scaleid = $forum->scale;
490         $ratingoptions->userid = $USER->id;
491         if ($forum->type == 'single' or !$discussion->id) {
492             $ratingoptions->returnurl = "$CFG->wwwroot/mod/forum/view.php?id=$cm->id";
493         } else {
494             $ratingoptions->returnurl = "$CFG->wwwroot/mod/forum/discuss.php?d=$discussion->id";
495         }
496         $ratingoptions->assesstimestart = $forum->assesstimestart;
497         $ratingoptions->assesstimefinish = $forum->assesstimefinish;
499         $rm = new rating_manager();
500         $posts = $rm->get_ratings($ratingoptions);
501     }
504     $post->forum = $forum->id;   // Add the forum id to the post object, later used by forum_print_post
505     $post->forumtype = $forum->type;
507     $post->subject = format_string($post->subject);
509     $postread = !empty($post->postread);
511     forum_print_post_start($post);
512     forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, false,
513                          '', '', $postread, true, $forumtracked);
515     switch ($mode) {
516         case FORUM_MODE_FLATOLDEST :
517         case FORUM_MODE_FLATNEWEST :
518         default:
519             forum_print_posts_flat($course, $cm, $forum, $discussion, $post, $mode, $reply, $forumtracked, $posts);
520             break;
522         case FORUM_MODE_THREADED :
523             forum_print_posts_threaded($course, $cm, $forum, $discussion, $post, 0, $reply, $forumtracked, $posts);
524             break;
526         case FORUM_MODE_NESTED :
527             forum_print_posts_nested($course, $cm, $forum, $discussion, $post, $reply, $forumtracked, $posts);
528             break;
529     }
530     forum_print_post_end($post);
534 /**
535  * Return a static array of posts that are open.
536  *
537  * @return array
538  * @deprecated since Moodle 3.7
539  */
540 function forum_post_nesting_cache() {
541     debugging('forum_post_nesting_cache() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
542     static $nesting = array();
543     return $nesting;
546 /**
547  * Return true for the first time this post was started
548  *
549  * @param int $id The id of the post to start
550  * @return bool
551  * @deprecated since Moodle 3.7
552  */
553 function forum_should_start_post_nesting($id) {
554     debugging('forum_should_start_post_nesting() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
555     $cache = forum_post_nesting_cache();
556     if (!array_key_exists($id, $cache)) {
557         $cache[$id] = 1;
558         return true;
559     } else {
560         $cache[$id]++;
561         return false;
562     }
565 /**
566  * Return true when all the opens are nested with a close.
567  *
568  * @param int $id The id of the post to end
569  * @return bool
570  * @deprecated since Moodle 3.7
571  */
572 function forum_should_end_post_nesting($id) {
573     debugging('forum_should_end_post_nesting() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
574     $cache = forum_post_nesting_cache();
575     if (!array_key_exists($id, $cache)) {
576         return true;
577     } else {
578         $cache[$id]--;
579         if ($cache[$id] == 0) {
580             unset($cache[$id]);
581             return true;
582         }
583     }
584     return false;
587 /**
588  * Start a forum post container
589  *
590  * @param object $post The post to print.
591  * @param bool $return Return the string or print it
592  * @return string
593  * @deprecated since Moodle 3.7
594  */
595 function forum_print_post_start($post, $return = false) {
596     debugging('forum_print_post_start() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
597     $output = '';
599     if (forum_should_start_post_nesting($post->id)) {
600         $attributes = [
601             'id' => 'p'.$post->id,
602             'tabindex' => -1,
603             'class' => 'relativelink'
604         ];
605         $output .= html_writer::start_tag('article', $attributes);
606     }
607     if ($return) {
608         return $output;
609     }
610     echo $output;
611     return;
614 /**
615  * End a forum post container
616  *
617  * @param object $post The post to print.
618  * @param bool $return Return the string or print it
619  * @return string
620  * @deprecated since Moodle 3.7
621  */
622 function forum_print_post_end($post, $return = false) {
623     debugging('forum_print_post_end() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
624     $output = '';
626     if (forum_should_end_post_nesting($post->id)) {
627         $output .= html_writer::end_tag('article');
628     }
629     if ($return) {
630         return $output;
631     }
632     echo $output;
633     return;
636 /**
637  * Print a forum post
638  * This function should always be surrounded with calls to forum_print_post_start
639  * and forum_print_post_end to create the surrounding container for the post.
640  * Replies can be nested before forum_print_post_end and should reflect the structure of
641  * thread.
642  *
643  * @global object
644  * @global object
645  * @uses FORUM_MODE_THREADED
646  * @uses PORTFOLIO_FORMAT_PLAINHTML
647  * @uses PORTFOLIO_FORMAT_FILE
648  * @uses PORTFOLIO_FORMAT_RICHHTML
649  * @uses PORTFOLIO_ADD_TEXT_LINK
650  * @uses CONTEXT_MODULE
651  * @param object $post The post to print.
652  * @param object $discussion
653  * @param object $forum
654  * @param object $cm
655  * @param object $course
656  * @param boolean $ownpost Whether this post belongs to the current user.
657  * @param boolean $reply Whether to print a 'reply' link at the bottom of the message.
658  * @param boolean $link Just print a shortened version of the post as a link to the full post.
659  * @param string $footer Extra stuff to print after the message.
660  * @param string $highlight Space-separated list of terms to highlight.
661  * @param int $post_read true, false or -99. If we already know whether this user
662  *          has read this post, pass that in, otherwise, pass in -99, and this
663  *          function will work it out.
664  * @param boolean $dummyifcantsee When forum_user_can_see_post says that
665  *          the current user can't see this post, if this argument is true
666  *          (the default) then print a dummy 'you can't see this post' post.
667  *          If false, don't output anything at all.
668  * @param bool|null $istracked
669  * @return void
670  * @deprecated since Moodle 3.7
671  */
672 function forum_print_post($post, $discussion, $forum, &$cm, $course, $ownpost=false, $reply=false, $link=false,
673                           $footer="", $highlight="", $postisread=null, $dummyifcantsee=true, $istracked=null, $return=false) {
674     debugging('forum_print_post() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
675     global $USER, $CFG, $OUTPUT;
677     require_once($CFG->libdir . '/filelib.php');
679     // String cache
680     static $str;
681     // This is an extremely hacky way to ensure we only print the 'unread' anchor
682     // the first time we encounter an unread post on a page. Ideally this would
683     // be moved into the caller somehow, and be better testable. But at the time
684     // of dealing with this bug, this static workaround was the most surgical and
685     // it fits together with only printing th unread anchor id once on a given page.
686     static $firstunreadanchorprinted = false;
688     $modcontext = context_module::instance($cm->id);
690     $post->course = $course->id;
691     $post->forum  = $forum->id;
692     $post->message = file_rewrite_pluginfile_urls($post->message, 'pluginfile.php', $modcontext->id, 'mod_forum', 'post', $post->id);
693     if (!empty($CFG->enableplagiarism)) {
694         require_once($CFG->libdir.'/plagiarismlib.php');
695         $post->message .= plagiarism_get_links(array('userid' => $post->userid,
696             'content' => $post->message,
697             'cmid' => $cm->id,
698             'course' => $post->course,
699             'forum' => $post->forum));
700     }
702     // caching
703     if (!isset($cm->cache)) {
704         $cm->cache = new stdClass;
705     }
707     if (!isset($cm->cache->caps)) {
708         $cm->cache->caps = array();
709         $cm->cache->caps['mod/forum:viewdiscussion']   = has_capability('mod/forum:viewdiscussion', $modcontext);
710         $cm->cache->caps['moodle/site:viewfullnames']  = has_capability('moodle/site:viewfullnames', $modcontext);
711         $cm->cache->caps['mod/forum:editanypost']      = has_capability('mod/forum:editanypost', $modcontext);
712         $cm->cache->caps['mod/forum:splitdiscussions'] = has_capability('mod/forum:splitdiscussions', $modcontext);
713         $cm->cache->caps['mod/forum:deleteownpost']    = has_capability('mod/forum:deleteownpost', $modcontext);
714         $cm->cache->caps['mod/forum:deleteanypost']    = has_capability('mod/forum:deleteanypost', $modcontext);
715         $cm->cache->caps['mod/forum:viewanyrating']    = has_capability('mod/forum:viewanyrating', $modcontext);
716         $cm->cache->caps['mod/forum:exportpost']       = has_capability('mod/forum:exportpost', $modcontext);
717         $cm->cache->caps['mod/forum:exportownpost']    = has_capability('mod/forum:exportownpost', $modcontext);
718     }
720     if (!isset($cm->uservisible)) {
721         $cm->uservisible = \core_availability\info_module::is_user_visible($cm, 0, false);
722     }
724     if ($istracked && is_null($postisread)) {
725         $postisread = forum_tp_is_post_read($USER->id, $post);
726     }
728     if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm, false)) {
729         // Do _not_ check the deleted flag - we need to display a different UI.
730         $output = '';
731         if (!$dummyifcantsee) {
732             if ($return) {
733                 return $output;
734             }
735             echo $output;
736             return;
737         }
739         $output .= html_writer::start_tag('div', array('class' => 'forumpost clearfix',
740                                                        'aria-label' => get_string('hiddenforumpost', 'forum')));
741         $output .= html_writer::start_tag('header', array('class' => 'row header'));
742         $output .= html_writer::tag('div', '', array('class' => 'left picture', 'role' => 'presentation')); // Picture.
743         if ($post->parent) {
744             $output .= html_writer::start_tag('div', array('class' => 'topic'));
745         } else {
746             $output .= html_writer::start_tag('div', array('class' => 'topic starter'));
747         }
748         $output .= html_writer::tag('div', get_string('forumsubjecthidden','forum'), array('class' => 'subject',
749                                                                                            'role' => 'header',
750                                                                                            'id' => ('headp' . $post->id))); // Subject.
751         $authorclasses = array('class' => 'author');
752         $output .= html_writer::tag('address', get_string('forumauthorhidden', 'forum'), $authorclasses); // Author.
753         $output .= html_writer::end_tag('div');
754         $output .= html_writer::end_tag('header'); // Header.
755         $output .= html_writer::start_tag('div', array('class'=>'row'));
756         $output .= html_writer::tag('div', '&nbsp;', array('class'=>'left side')); // Groups
757         $output .= html_writer::tag('div', get_string('forumbodyhidden','forum'), array('class'=>'content')); // Content
758         $output .= html_writer::end_tag('div'); // row
759         $output .= html_writer::end_tag('div'); // forumpost
761         if ($return) {
762             return $output;
763         }
764         echo $output;
765         return;
766     }
768     if (!empty($post->deleted)) {
769         // Note: Posts marked as deleted are still returned by the above forum_user_can_post because it is required for
770         // nesting of posts.
771         $output = '';
772         if (!$dummyifcantsee) {
773             if ($return) {
774                 return $output;
775             }
776             echo $output;
777             return;
778         }
779         $output .= html_writer::start_tag('div', [
780                 'class' => 'forumpost clearfix',
781                 'aria-label' => get_string('forumbodydeleted', 'forum'),
782             ]);
784         $output .= html_writer::start_tag('header', array('class' => 'row header'));
785         $output .= html_writer::tag('div', '', array('class' => 'left picture', 'role' => 'presentation'));
787         $classes = ['topic'];
788         if (!empty($post->parent)) {
789             $classes[] = 'starter';
790         }
791         $output .= html_writer::start_tag('div', ['class' => implode(' ', $classes)]);
793         // Subject.
794         $output .= html_writer::tag('div', get_string('forumsubjectdeleted', 'forum'), [
795                 'class' => 'subject',
796                 'role' => 'header',
797                 'id' => ('headp' . $post->id)
798             ]);
800         // Author.
801         $output .= html_writer::tag('address', '', ['class' => 'author']);
803         $output .= html_writer::end_tag('div');
804         $output .= html_writer::end_tag('header'); // End header.
805         $output .= html_writer::start_tag('div', ['class' => 'row']);
806         $output .= html_writer::tag('div', '&nbsp;', ['class' => 'left side']); // Groups.
807         $output .= html_writer::tag('div', get_string('forumbodydeleted', 'forum'), ['class' => 'content']); // Content.
808         $output .= html_writer::end_tag('div'); // End row.
809         $output .= html_writer::end_tag('div'); // End forumpost.
811         if ($return) {
812             return $output;
813         }
814         echo $output;
815         return;
816     }
818     if (empty($str)) {
819         $str = new stdClass;
820         $str->edit         = get_string('edit', 'forum');
821         $str->delete       = get_string('delete', 'forum');
822         $str->reply        = get_string('reply', 'forum');
823         $str->parent       = get_string('parent', 'forum');
824         $str->pruneheading = get_string('pruneheading', 'forum');
825         $str->prune        = get_string('prune', 'forum');
826         $str->displaymode     = get_user_preferences('forum_displaymode', $CFG->forum_displaymode);
827         $str->markread     = get_string('markread', 'forum');
828         $str->markunread   = get_string('markunread', 'forum');
829     }
831     $discussionlink = new moodle_url('/mod/forum/discuss.php', array('d'=>$post->discussion));
833     // Build an object that represents the posting user
834     $postuser = new stdClass;
835     $postuserfields = explode(',', user_picture::fields());
836     $postuser = username_load_fields_from_object($postuser, $post, null, $postuserfields);
837     $postuser->id = $post->userid;
838     $postuser->fullname    = fullname($postuser, $cm->cache->caps['moodle/site:viewfullnames']);
839     $postuser->profilelink = new moodle_url('/user/view.php', array('id'=>$post->userid, 'course'=>$course->id));
841     // Prepare the groups the posting user belongs to
842     if (isset($cm->cache->usersgroups)) {
843         $groups = array();
844         if (isset($cm->cache->usersgroups[$post->userid])) {
845             foreach ($cm->cache->usersgroups[$post->userid] as $gid) {
846                 $groups[$gid] = $cm->cache->groups[$gid];
847             }
848         }
849     } else {
850         $groups = groups_get_all_groups($course->id, $post->userid, $cm->groupingid);
851     }
853     // Prepare the attachements for the post, files then images
854     list($attachments, $attachedimages) = forum_print_attachments($post, $cm, 'separateimages');
856     // Determine if we need to shorten this post
857     $shortenpost = ($link && (strlen(strip_tags($post->message)) > $CFG->forum_longpost));
859     // Prepare an array of commands
860     $commands = array();
862     // Add a permalink.
863     $permalink = new moodle_url($discussionlink);
864     $permalink->set_anchor('p' . $post->id);
865     $commands[] = array('url' => $permalink, 'text' => get_string('permalink', 'forum'), 'attributes' => ['rel' => 'bookmark']);
867     // SPECIAL CASE: The front page can display a news item post to non-logged in users.
868     // Don't display the mark read / unread controls in this case.
869     if ($istracked && $CFG->forum_usermarksread && isloggedin()) {
870         $url = new moodle_url($discussionlink, array('postid'=>$post->id, 'mark'=>'unread'));
871         $text = $str->markunread;
872         if (!$postisread) {
873             $url->param('mark', 'read');
874             $text = $str->markread;
875         }
876         if ($str->displaymode == FORUM_MODE_THREADED) {
877             $url->param('parent', $post->parent);
878         } else {
879             $url->set_anchor('p'.$post->id);
880         }
881         $commands[] = array('url'=>$url, 'text'=>$text, 'attributes' => ['rel' => 'bookmark']);
882     }
884     // Zoom in to the parent specifically
885     if ($post->parent) {
886         $url = new moodle_url($discussionlink);
887         if ($str->displaymode == FORUM_MODE_THREADED) {
888             $url->param('parent', $post->parent);
889         } else {
890             $url->set_anchor('p'.$post->parent);
891         }
892         $commands[] = array('url'=>$url, 'text'=>$str->parent, 'attributes' => ['rel' => 'bookmark']);
893     }
895     // Hack for allow to edit news posts those are not displayed yet until they are displayed
896     $age = time() - $post->created;
897     if (!$post->parent && $forum->type == 'news' && $discussion->timestart > time()) {
898         $age = 0;
899     }
901     if ($forum->type == 'single' and $discussion->firstpost == $post->id) {
902         if (has_capability('moodle/course:manageactivities', $modcontext)) {
903             // The first post in single simple is the forum description.
904             $commands[] = array('url'=>new moodle_url('/course/modedit.php', array('update'=>$cm->id, 'sesskey'=>sesskey(), 'return'=>1)), 'text'=>$str->edit);
905         }
906     } else if (($ownpost && $age < $CFG->maxeditingtime) || $cm->cache->caps['mod/forum:editanypost']) {
907         $commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('edit'=>$post->id)), 'text'=>$str->edit);
908     }
910     if ($cm->cache->caps['mod/forum:splitdiscussions'] && $post->parent && $forum->type != 'single') {
911         $commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('prune'=>$post->id)), 'text'=>$str->prune, 'title'=>$str->pruneheading);
912     }
914     if ($forum->type == 'single' and $discussion->firstpost == $post->id) {
915         // Do not allow deleting of first post in single simple type.
916     } else if (($ownpost && $age < $CFG->maxeditingtime && $cm->cache->caps['mod/forum:deleteownpost']) || $cm->cache->caps['mod/forum:deleteanypost']) {
917         $commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('delete'=>$post->id)), 'text'=>$str->delete);
918     }
920     if ($reply) {
921         $commands[] = array('url'=>new moodle_url('/mod/forum/post.php#mformforum', array('reply'=>$post->id)), 'text'=>$str->reply);
922     }
924     if ($CFG->enableportfolios && ($cm->cache->caps['mod/forum:exportpost'] || ($ownpost && $cm->cache->caps['mod/forum:exportownpost']))) {
925         $p = array('postid' => $post->id);
926         require_once($CFG->libdir.'/portfoliolib.php');
927         $button = new portfolio_add_button();
928         $button->set_callback_options('forum_portfolio_caller', array('postid' => $post->id), 'mod_forum');
929         if (empty($attachments)) {
930             $button->set_formats(PORTFOLIO_FORMAT_PLAINHTML);
931         } else {
932             $button->set_formats(PORTFOLIO_FORMAT_RICHHTML);
933         }
935         $porfoliohtml = $button->to_html(PORTFOLIO_ADD_TEXT_LINK);
936         if (!empty($porfoliohtml)) {
937             $commands[] = $porfoliohtml;
938         }
939     }
940     // Finished building commands
943     // Begin output
945     $output  = '';
947     if ($istracked) {
948         if ($postisread) {
949             $forumpostclass = ' read';
950         } else {
951             $forumpostclass = ' unread';
952             // If this is the first unread post printed then give it an anchor and id of unread.
953             if (!$firstunreadanchorprinted) {
954                 $output .= html_writer::tag('a', '', array('id' => 'unread'));
955                 $firstunreadanchorprinted = true;
956             }
957         }
958     } else {
959         // ignore trackign status if not tracked or tracked param missing
960         $forumpostclass = '';
961     }
963     $topicclass = '';
964     if (empty($post->parent)) {
965         $topicclass = ' firstpost starter';
966     }
968     if (!empty($post->lastpost)) {
969         $forumpostclass .= ' lastpost';
970     }
972     // Flag to indicate whether we should hide the author or not.
973     $authorhidden = forum_is_author_hidden($post, $forum);
974     $postbyuser = new stdClass;
975     $postbyuser->post = $post->subject;
976     $postbyuser->user = $postuser->fullname;
977     $discussionbyuser = get_string('postbyuser', 'forum', $postbyuser);
978     // Begin forum post.
979     $output .= html_writer::start_div('forumpost clearfix' . $forumpostclass . $topicclass,
980         ['aria-label' => $discussionbyuser]);
981     // Begin header row.
982     $output .= html_writer::start_tag('header', ['class' => 'row header clearfix']);
984     // User picture.
985     if (!$authorhidden) {
986         $picture = $OUTPUT->user_picture($postuser, ['courseid' => $course->id]);
987         $output .= html_writer::div($picture, 'left picture', ['role' => 'presentation']);
988         $topicclass = 'topic' . $topicclass;
989     }
991     // Begin topic column.
992     $output .= html_writer::start_div($topicclass);
993     $postsubject = $post->subject;
994     if (empty($post->subjectnoformat)) {
995         $postsubject = format_string($postsubject);
996     }
997     $output .= html_writer::div($postsubject, 'subject', ['role' => 'heading', 'aria-level' => '1', 'id' => ('headp' . $post->id)]);
999     if ($authorhidden) {
1000         $bytext = userdate_htmltime($post->created);
1001     } else {
1002         $by = new stdClass();
1003         $by->date = userdate_htmltime($post->created);
1004         $by->name = html_writer::link($postuser->profilelink, $postuser->fullname);
1005         $bytext = get_string('bynameondate', 'forum', $by);
1006     }
1007     $bytextoptions = [
1008         'class' => 'author'
1009     ];
1010     $output .= html_writer::tag('address', $bytext, $bytextoptions);
1011     // End topic column.
1012     $output .= html_writer::end_div();
1014     // End header row.
1015     $output .= html_writer::end_tag('header');
1017     // Row with the forum post content.
1018     $output .= html_writer::start_div('row maincontent clearfix');
1019     // Show if author is not hidden or we have groups.
1020     if (!$authorhidden || $groups) {
1021         $output .= html_writer::start_div('left');
1022         $groupoutput = '';
1023         if ($groups) {
1024             $groupoutput = print_group_picture($groups, $course->id, false, true, true);
1025         }
1026         if (empty($groupoutput)) {
1027             $groupoutput = '&nbsp;';
1028         }
1029         $output .= html_writer::div($groupoutput, 'grouppictures');
1030         $output .= html_writer::end_div(); // Left side.
1031     }
1033     $output .= html_writer::start_tag('div', array('class'=>'no-overflow'));
1034     $output .= html_writer::start_tag('div', array('class'=>'content'));
1036     $options = new stdClass;
1037     $options->para    = false;
1038     $options->trusted = $post->messagetrust;
1039     $options->context = $modcontext;
1040     if ($shortenpost) {
1041         // Prepare shortened version by filtering the text then shortening it.
1042         $postclass    = 'shortenedpost';
1043         $postcontent  = format_text($post->message, $post->messageformat, $options);
1044         $postcontent  = shorten_text($postcontent, $CFG->forum_shortpost);
1045         $postcontent .= html_writer::link($discussionlink, get_string('readtherest', 'forum'));
1046         $postcontent .= html_writer::tag('div', '('.get_string('numwords', 'moodle', count_words($post->message)).')',
1047             array('class'=>'post-word-count'));
1048     } else {
1049         // Prepare whole post
1050         $postclass    = 'fullpost';
1051         $postcontent  = format_text($post->message, $post->messageformat, $options, $course->id);
1052         if (!empty($highlight)) {
1053             $postcontent = highlight($highlight, $postcontent);
1054         }
1055         if (!empty($forum->displaywordcount)) {
1056             $postcontent .= html_writer::tag('div', get_string('numwords', 'moodle', count_words($postcontent)),
1057                 array('class'=>'post-word-count'));
1058         }
1059         $postcontent .= html_writer::tag('div', $attachedimages, array('class'=>'attachedimages'));
1060     }
1062     if (\core_tag_tag::is_enabled('mod_forum', 'forum_posts')) {
1063         $postcontent .= $OUTPUT->tag_list(core_tag_tag::get_item_tags('mod_forum', 'forum_posts', $post->id), null, 'forum-tags');
1064     }
1066     // Output the post content
1067     $output .= html_writer::tag('div', $postcontent, array('class'=>'posting '.$postclass));
1068     $output .= html_writer::end_tag('div'); // Content
1069     $output .= html_writer::end_tag('div'); // Content mask
1070     $output .= html_writer::end_tag('div'); // Row
1072     $output .= html_writer::start_tag('nav', array('class' => 'row side'));
1073     $output .= html_writer::tag('div','&nbsp;', array('class'=>'left'));
1074     $output .= html_writer::start_tag('div', array('class'=>'options clearfix'));
1076     if (!empty($attachments)) {
1077         $output .= html_writer::tag('div', $attachments, array('class' => 'attachments'));
1078     }
1080     // Output ratings
1081     if (!empty($post->rating)) {
1082         $output .= html_writer::tag('div', $OUTPUT->render($post->rating), array('class'=>'forum-post-rating'));
1083     }
1085     // Output the commands
1086     $commandhtml = array();
1087     foreach ($commands as $command) {
1088         if (is_array($command)) {
1089             $attributes = ['class' => 'nav-item nav-link'];
1090             if (isset($command['attributes'])) {
1091                 $attributes = array_merge($attributes, $command['attributes']);
1092             }
1093             $commandhtml[] = html_writer::link($command['url'], $command['text'], $attributes);
1094         } else {
1095             $commandhtml[] = $command;
1096         }
1097     }
1098     $output .= html_writer::tag('div', implode(' ', $commandhtml), array('class' => 'commands nav'));
1100     // Output link to post if required
1101     if ($link) {
1102         if (forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext)) {
1103             $langstring = 'discussthistopic';
1104         } else {
1105             $langstring = 'viewthediscussion';
1106         }
1107         if ($post->replies == 1) {
1108             $replystring = get_string('repliesone', 'forum', $post->replies);
1109         } else {
1110             $replystring = get_string('repliesmany', 'forum', $post->replies);
1111         }
1112         if (!empty($discussion->unread) && $discussion->unread !== '-') {
1113             $replystring .= ' <span class="sep">/</span> <span class="unread">';
1114             $unreadlink = new moodle_url($discussionlink, null, 'unread');
1115             if ($discussion->unread == 1) {
1116                 $replystring .= html_writer::link($unreadlink, get_string('unreadpostsone', 'forum'));
1117             } else {
1118                 $replystring .= html_writer::link($unreadlink, get_string('unreadpostsnumber', 'forum', $discussion->unread));
1119             }
1120             $replystring .= '</span>';
1121         }
1123         $output .= html_writer::start_tag('div', array('class'=>'link'));
1124         $output .= html_writer::link($discussionlink, get_string($langstring, 'forum'));
1125         $output .= '&nbsp;('.$replystring.')';
1126         $output .= html_writer::end_tag('div'); // link
1127     }
1129     // Output footer if required
1130     if ($footer) {
1131         $output .= html_writer::tag('div', $footer, array('class'=>'footer'));
1132     }
1134     // Close remaining open divs
1135     $output .= html_writer::end_tag('div'); // content
1136     $output .= html_writer::end_tag('nav'); // row
1137     $output .= html_writer::end_tag('div'); // forumpost
1139     // Mark the forum post as read if required
1140     if ($istracked && !$CFG->forum_usermarksread && !$postisread) {
1141         forum_tp_mark_post_read($USER->id, $post);
1142     }
1144     if ($return) {
1145         return $output;
1146     }
1147     echo $output;
1148     return;
1151 /**
1152  * @global object
1153  * @global object
1154  * @uses FORUM_MODE_FLATNEWEST
1155  * @param object $course
1156  * @param object $cm
1157  * @param object $forum
1158  * @param object $discussion
1159  * @param object $post
1160  * @param object $mode
1161  * @param bool $reply
1162  * @param bool $forumtracked
1163  * @param array $posts
1164  * @return void
1165  * @deprecated since Moodle 3.7
1166  */
1167 function forum_print_posts_flat($course, &$cm, $forum, $discussion, $post, $mode, $reply, $forumtracked, $posts) {
1168     debugging('forum_print_posts_flat() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
1169     global $USER, $CFG;
1171     $link  = false;
1173     foreach ($posts as $post) {
1174         if (!$post->parent) {
1175             continue;
1176         }
1177         $post->subject = format_string($post->subject);
1178         $ownpost = ($USER->id == $post->userid);
1180         $postread = !empty($post->postread);
1182         forum_print_post_start($post);
1183         forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
1184                              '', '', $postread, true, $forumtracked);
1185         forum_print_post_end($post);
1186     }
1189 /**
1190  * @todo Document this function
1191  *
1192  * @global object
1193  * @global object
1194  * @uses CONTEXT_MODULE
1195  * @return void
1196  * @deprecated since Moodle 3.7
1197  */
1198 function forum_print_posts_threaded($course, &$cm, $forum, $discussion, $parent, $depth, $reply, $forumtracked, $posts) {
1199     debugging('forum_print_posts_threaded() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
1200     global $USER, $CFG;
1202     $link  = false;
1204     if (!empty($posts[$parent->id]->children)) {
1205         $posts = $posts[$parent->id]->children;
1207         $modcontext       = context_module::instance($cm->id);
1208         $canviewfullnames = has_capability('moodle/site:viewfullnames', $modcontext);
1210         foreach ($posts as $post) {
1212             echo '<div class="indent">';
1213             if ($depth > 0) {
1214                 $ownpost = ($USER->id == $post->userid);
1215                 $post->subject = format_string($post->subject);
1217                 $postread = !empty($post->postread);
1219                 forum_print_post_start($post);
1220                 forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
1221                                      '', '', $postread, true, $forumtracked);
1222                 forum_print_post_end($post);
1223             } else {
1224                 if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm, true)) {
1225                     if (forum_user_can_see_post($forum, $discussion, $post, null, $cm, false)) {
1226                         // This post has been deleted but still exists and may have children.
1227                         $subject = get_string('privacy:request:delete:post:subject', 'mod_forum');
1228                         $byline = '';
1229                     } else {
1230                         // The user can't see this post at all.
1231                         echo "</div>\n";
1232                         continue;
1233                     }
1234                 } else {
1235                     $by = new stdClass();
1236                     $by->name = fullname($post, $canviewfullnames);
1237                     $by->date = userdate_htmltime($post->modified);
1238                     $byline = ' ' . get_string("bynameondate", "forum", $by);
1239                     $subject = format_string($post->subject, true);
1240                 }
1242                 if ($forumtracked) {
1243                     if (!empty($post->postread)) {
1244                         $style = '<span class="forumthread read">';
1245                     } else {
1246                         $style = '<span class="forumthread unread">';
1247                     }
1248                 } else {
1249                     $style = '<span class="forumthread">';
1250                 }
1252                 echo $style;
1253                 echo "<a name='{$post->id}'></a>";
1254                 echo html_writer::link(new moodle_url('/mod/forum/discuss.php', [
1255                         'd' => $post->discussion,
1256                         'parent' => $post->id,
1257                     ]), $subject);
1258                 echo $byline;
1259                 echo "</span>";
1260             }
1262             forum_print_posts_threaded($course, $cm, $forum, $discussion, $post, $depth-1, $reply, $forumtracked, $posts);
1263             echo "</div>\n";
1264         }
1265     }
1268 /**
1269  * @todo Document this function
1270  * @global object
1271  * @global object
1272  * @return void
1273  * @deprecated since Moodle 3.7
1274  */
1275 function forum_print_posts_nested($course, &$cm, $forum, $discussion, $parent, $reply, $forumtracked, $posts) {
1276     debugging('forum_print_posts_nested() has been deprecated, please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
1277     global $USER, $CFG;
1279     $link  = false;
1281     if (!empty($posts[$parent->id]->children)) {
1282         $posts = $posts[$parent->id]->children;
1284         foreach ($posts as $post) {
1286             echo '<div class="indent">';
1287             if (!isloggedin()) {
1288                 $ownpost = false;
1289             } else {
1290                 $ownpost = ($USER->id == $post->userid);
1291             }
1293             $post->subject = format_string($post->subject);
1294             $postread = !empty($post->postread);
1296             forum_print_post_start($post);
1297             forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
1298                                  '', '', $postread, true, $forumtracked);
1299             forum_print_posts_nested($course, $cm, $forum, $discussion, $post, $reply, $forumtracked, $posts);
1300             forum_print_post_end($post);
1301             echo "</div>\n";
1302         }
1303     }