weekly release 4.0dev
[moodle.git] / mod / forum / deprecatedlib.php
CommitLineData
39de876c
AN
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/>.
16
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 */
22
23defined('MOODLE_INTERNAL') || die();
24
25// Deprecated a very long time ago.
26
27/**
39de876c
AN
28 * @deprecated since Moodle 1.1 - please do not use this function any more.
29 */
d16185fd
AN
30function forum_count_unrated_posts() {
31 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
32}
33
34
35// Since Moodle 1.5.
36
37/**
39de876c
AN
38 * @deprecated since Moodle 1.5 - please do not use this function any more.
39 */
d16185fd
AN
40function forum_tp_count_discussion_read_records() {
41 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
42}
43
44/**
39de876c
AN
45 * @deprecated since Moodle 1.5 - please do not use this function any more.
46 */
d16185fd
AN
47function forum_get_user_discussions() {
48 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
49}
50
51
52// Since Moodle 1.6.
53
54/**
39de876c
AN
55 * @deprecated since Moodle 1.6 - please do not use this function any more.
56 */
d16185fd
AN
57function forum_tp_count_forum_posts() {
58 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
59}
60
61/**
39de876c
AN
62 * @deprecated since Moodle 1.6 - please do not use this function any more.
63 */
d16185fd
AN
64function forum_tp_count_forum_read_records() {
65 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
66}
67
68
69// Since Moodle 1.7.
70
71/**
39de876c
AN
72 * @deprecated since Moodle 1.7 - please do not use this function any more.
73 */
74function forum_get_open_modes() {
d16185fd 75 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
76}
77
78
79// Since Moodle 1.9.
80
81/**
39de876c
AN
82 * @deprecated since Moodle 1.9 MDL-13303 - please do not use this function any more.
83 */
d16185fd
AN
84function forum_get_child_posts() {
85 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
86}
87
88/**
39de876c
AN
89 * @deprecated since Moodle 1.9 MDL-13303 - please do not use this function any more.
90 */
d16185fd
AN
91function forum_get_discussion_posts() {
92 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
93}
94
95
96// Since Moodle 2.0.
97
98/**
39de876c
AN
99 * @deprecated since Moodle 2.0 MDL-21657 - please do not use this function any more.
100 */
d16185fd
AN
101function forum_get_ratings() {
102 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
103}
104
105/**
39de876c
AN
106 * @deprecated since Moodle 2.0 MDL-14632 - please do not use this function any more.
107 */
d16185fd
AN
108function forum_get_tracking_link() {
109 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
110}
111
112/**
39de876c
AN
113 * @deprecated since Moodle 2.0 MDL-14113 - please do not use this function any more.
114 */
d16185fd
AN
115function forum_tp_count_discussion_unread_posts() {
116 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
117}
118
119/**
39de876c
AN
120 * @deprecated since Moodle 2.0 MDL-23479 - please do not use this function any more.
121 */
122function forum_convert_to_roles() {
d16185fd 123 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
124}
125
126/**
39de876c
AN
127 * @deprecated since Moodle 2.0 MDL-14113 - please do not use this function any more.
128 */
d16185fd
AN
129function forum_tp_get_read_records() {
130 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
131}
132
133/**
39de876c
AN
134 * @deprecated since Moodle 2.0 MDL-14113 - please do not use this function any more.
135 */
d16185fd
AN
136function forum_tp_get_discussion_read_records() {
137 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
138}
139
140// Deprecated in 2.3.
141
142/**
39de876c 143 * @deprecated since Moodle 2.3 MDL-33166 - please do not use this function any more.
39de876c 144 */
d16185fd
AN
145function forum_user_enrolled() {
146 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
147}
148
149
150// Deprecated in 2.4.
151
152/**
39de876c 153 * @deprecated since Moodle 2.4 use forum_user_can_see_post() instead
39de876c 154 */
d16185fd
AN
155function forum_user_can_view_post() {
156 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
39de876c
AN
157}
158
159
160// Deprecated in 2.6.
161
162/**
163 * FORUM_TRACKING_ON - deprecated alias for FORUM_TRACKING_FORCED.
164 * @deprecated since 2.6
165 */
166define('FORUM_TRACKING_ON', 2);
167
168/**
39de876c
AN
169 * @deprecated since Moodle 2.6
170 * @see shorten_text()
39de876c
AN
171 */
172function forum_shorten_post($message) {
d16185fd
AN
173 throw new coding_exception(__FUNCTION__ . '() can not be used any more. '
174 . 'Please use shorten_text($message, $CFG->forum_shortpost) instead.');
39de876c 175}
59075a43
AN
176
177// Deprecated in 2.8.
178
179/**
59075a43
AN
180 * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::is_subscribed() instead
181 */
d16185fd
AN
182function forum_is_subscribed() {
183 throw new coding_exception(__FUNCTION__ . '() can not be used any more.');
59075a43
AN
184}
185
186/**
59075a43
AN
187 * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::subscribe_user() instead
188 */
d16185fd
AN
189function forum_subscribe() {
190 throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
191 . \mod_forum\subscriptions::class . '::subscribe_user() instead');
59075a43
AN
192}
193
194/**
59075a43
AN
195 * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::unsubscribe_user() instead
196 */
d16185fd
AN
197function forum_unsubscribe() {
198 throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
199 . \mod_forum\subscriptions::class . '::unsubscribe_user() instead');
59075a43
AN
200}
201
202/**
59075a43
AN
203 * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::fetch_subscribed_users() instead
204 */
d16185fd
AN
205function 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');
59075a43
AN
208}
209
210/**
211 * Determine whether the forum is force subscribed.
212 *
59075a43
AN
213 * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::is_forcesubscribed() instead
214 */
215function forum_is_forcesubscribed($forum) {
d16185fd
AN
216 throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
217 . \mod_forum\subscriptions::class . '::is_forcesubscribed() instead');
59075a43
AN
218}
219
220/**
59075a43
AN
221 * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::set_subscription_mode() instead
222 */
223function forum_forcesubscribe($forumid, $value = 1) {
d16185fd
AN
224 throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
225 . \mod_forum\subscriptions::class . '::set_subscription_mode() instead');
59075a43
AN
226}
227
228/**
59075a43
AN
229 * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::get_subscription_mode() instead
230 */
231function forum_get_forcesubscribed($forum) {
d16185fd
AN
232 throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
233 . \mod_forum\subscriptions::class . '::set_subscription_mode() instead');
59075a43
AN
234}
235
236/**
59075a43
AN
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 */
d16185fd
AN
240function 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');
59075a43
AN
244}
245
246/**
59075a43
AN
247 * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::get_unsubscribable_forums() instead
248 */
249function forum_get_optional_subscribed_forums() {
d16185fd
AN
250 throw new coding_exception(__FUNCTION__ . '() can not be used any more. Please use '
251 . \mod_forum\subscriptions::class . '::get_unsubscribable_forums() instead');
59075a43
AN
252}
253
254/**
59075a43
AN
255 * @deprecated since Moodle 2.8 use \mod_forum\subscriptions::get_potential_subscribers() instead
256 */
d16185fd
AN
257function 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');
59075a43 260}
31793839
AN
261
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 */
278function 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 );
290
291 $modcontext = context_module::instance($cm->id);
292 $renderable->viewfullnames = has_capability('moodle/site:viewfullnames', $modcontext, $userto->id);
293
294 if ($bare) {
295 $renderer = $PAGE->get_renderer('mod_forum', 'emaildigestfull', 'textemail');
296 } else {
297 $renderer = $PAGE->get_renderer('mod_forum', 'email', 'textemail');
298 }
299
300 debugging("forum_make_mail_text() has been deprecated, please use the \mod_forum\output\forum_post_email renderable instead.",
301 DEBUG_DEVELOPER);
302
303 return $renderer->render($renderable);
304}
305
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 */
320function 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 );
330}
331
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 */
351function 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);
363
364 $modcontext = context_module::instance($cm->id);
365 $renderable->viewfullnames = has_capability('moodle/site:viewfullnames', $modcontext, $userto->id);
366
367 // Assume that this is being used as a standard forum email.
368 $renderer = $PAGE->get_renderer('mod_forum', 'email', 'htmlemail');
369
370 debugging("forum_make_mail_post() has been deprecated, please use the \mod_forum\output\forum_post_email renderable instead.",
371 DEBUG_DEVELOPER);
372
373 return $renderer->render($renderable);
374}
4459ad29
AN
375
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 */
383function 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);
386
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.
390
391 unset($user->institution);
392 unset($user->department);
393 unset($user->address);
394 unset($user->city);
4459ad29
AN
395 unset($user->currentlogin);
396 unset($user->description);
397 unset($user->descriptionformat);
398}
399
400/**
401 * Function to be run periodically according to the scheduled task.
402 *
403 * Finds all posts that have yet to be mailed out, and mails them out to all subscribers as well as other maintance
404 * tasks.
405 *
406 * @deprecated since Moodle 3.7
407 */
408function forum_cron() {
409 debugging("forum_cron() has been deprecated and replaced with new tasks. Please uses these instead.",
410 DEBUG_DEVELOPER);
411}
2e19ca18
RW
412
413/**
414 * Prints a forum discussion
415 *
416 * @uses CONTEXT_MODULE
417 * @uses FORUM_MODE_FLATNEWEST
418 * @uses FORUM_MODE_FLATOLDEST
419 * @uses FORUM_MODE_THREADED
420 * @uses FORUM_MODE_NESTED
421 * @param stdClass $course
422 * @param stdClass $cm
423 * @param stdClass $forum
424 * @param stdClass $discussion
425 * @param stdClass $post
426 * @param int $mode
427 * @param mixed $canreply
428 * @param bool $canrate
429 * @deprecated since Moodle 3.7
430 */
431function forum_print_discussion($course, $cm, $forum, $discussion, $post, $mode, $canreply=NULL, $canrate=false) {
f30f46db
RW
432 debugging('forum_print_discussion() has been deprecated, ' .
433 'please use \mod_forum\local\renderers\discussion instead.', DEBUG_DEVELOPER);
2e19ca18
RW
434
435 global $USER, $CFG;
436
437 require_once($CFG->dirroot.'/rating/lib.php');
438
439 $ownpost = (isloggedin() && $USER->id == $post->userid);
440
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 }
447
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();
452
453 $posters = array();
454
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 }
461
462 $forumtracked = forum_tp_is_tracked($forum);
463 $posts = forum_get_all_discussion_posts($discussion->id, $sort, $forumtracked);
464 $post = $posts[$post->id];
465
466 foreach ($posts as $pid=>$p) {
467 $posters[$p->userid] = $p->userid;
468 }
469
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 }
480
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;
498
499 $rm = new rating_manager();
500 $posts = $rm->get_ratings($ratingoptions);
501 }
502
503
504 $post->forum = $forum->id; // Add the forum id to the post object, later used by forum_print_post
505 $post->forumtype = $forum->type;
506
507 $post->subject = format_string($post->subject);
508
509 $postread = !empty($post->postread);
510
511 forum_print_post_start($post);
512 forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, false,
513 '', '', $postread, true, $forumtracked);
514
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;
521
522 case FORUM_MODE_THREADED :
523 forum_print_posts_threaded($course, $cm, $forum, $discussion, $post, 0, $reply, $forumtracked, $posts);
524 break;
525
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);
531}
532
533
534/**
535 * Return a static array of posts that are open.
536 *
537 * @return array
538 * @deprecated since Moodle 3.7
539 */
540function forum_post_nesting_cache() {
f30f46db
RW
541 debugging('forum_post_nesting_cache() has been deprecated, ' .
542 'please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
2e19ca18
RW
543 static $nesting = array();
544 return $nesting;
545}
546
547/**
548 * Return true for the first time this post was started
549 *
550 * @param int $id The id of the post to start
551 * @return bool
552 * @deprecated since Moodle 3.7
553 */
554function forum_should_start_post_nesting($id) {
f30f46db
RW
555 debugging('forum_should_start_post_nesting() has been deprecated, ' .
556 'please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
2e19ca18
RW
557 $cache = forum_post_nesting_cache();
558 if (!array_key_exists($id, $cache)) {
559 $cache[$id] = 1;
560 return true;
561 } else {
562 $cache[$id]++;
563 return false;
564 }
565}
566
567/**
568 * Return true when all the opens are nested with a close.
569 *
570 * @param int $id The id of the post to end
571 * @return bool
572 * @deprecated since Moodle 3.7
573 */
574function forum_should_end_post_nesting($id) {
f30f46db
RW
575 debugging('forum_should_end_post_nesting() has been deprecated, ' .
576 'please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
2e19ca18
RW
577 $cache = forum_post_nesting_cache();
578 if (!array_key_exists($id, $cache)) {
579 return true;
580 } else {
581 $cache[$id]--;
582 if ($cache[$id] == 0) {
583 unset($cache[$id]);
584 return true;
585 }
586 }
587 return false;
588}
589
590/**
591 * Start a forum post container
592 *
593 * @param object $post The post to print.
594 * @param bool $return Return the string or print it
595 * @return string
596 * @deprecated since Moodle 3.7
597 */
598function forum_print_post_start($post, $return = false) {
f30f46db
RW
599 debugging('forum_print_post_start() has been deprecated, ' .
600 'please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
2e19ca18
RW
601 $output = '';
602
603 if (forum_should_start_post_nesting($post->id)) {
604 $attributes = [
605 'id' => 'p'.$post->id,
606 'tabindex' => -1,
607 'class' => 'relativelink'
608 ];
609 $output .= html_writer::start_tag('article', $attributes);
610 }
611 if ($return) {
612 return $output;
613 }
614 echo $output;
615 return;
616}
617
618/**
619 * End a forum post container
620 *
621 * @param object $post The post to print.
622 * @param bool $return Return the string or print it
623 * @return string
624 * @deprecated since Moodle 3.7
625 */
626function forum_print_post_end($post, $return = false) {
f30f46db
RW
627 debugging('forum_print_post_end() has been deprecated, ' .
628 'please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
2e19ca18
RW
629 $output = '';
630
631 if (forum_should_end_post_nesting($post->id)) {
632 $output .= html_writer::end_tag('article');
633 }
634 if ($return) {
635 return $output;
636 }
637 echo $output;
638 return;
639}
640
641/**
642 * Print a forum post
643 * This function should always be surrounded with calls to forum_print_post_start
644 * and forum_print_post_end to create the surrounding container for the post.
645 * Replies can be nested before forum_print_post_end and should reflect the structure of
646 * thread.
647 *
648 * @global object
649 * @global object
650 * @uses FORUM_MODE_THREADED
651 * @uses PORTFOLIO_FORMAT_PLAINHTML
652 * @uses PORTFOLIO_FORMAT_FILE
653 * @uses PORTFOLIO_FORMAT_RICHHTML
654 * @uses PORTFOLIO_ADD_TEXT_LINK
655 * @uses CONTEXT_MODULE
656 * @param object $post The post to print.
657 * @param object $discussion
658 * @param object $forum
659 * @param object $cm
660 * @param object $course
661 * @param boolean $ownpost Whether this post belongs to the current user.
662 * @param boolean $reply Whether to print a 'reply' link at the bottom of the message.
663 * @param boolean $link Just print a shortened version of the post as a link to the full post.
664 * @param string $footer Extra stuff to print after the message.
665 * @param string $highlight Space-separated list of terms to highlight.
666 * @param int $post_read true, false or -99. If we already know whether this user
667 * has read this post, pass that in, otherwise, pass in -99, and this
668 * function will work it out.
669 * @param boolean $dummyifcantsee When forum_user_can_see_post says that
670 * the current user can't see this post, if this argument is true
671 * (the default) then print a dummy 'you can't see this post' post.
672 * If false, don't output anything at all.
673 * @param bool|null $istracked
674 * @return void
675 * @deprecated since Moodle 3.7
676 */
677function forum_print_post($post, $discussion, $forum, &$cm, $course, $ownpost=false, $reply=false, $link=false,
678 $footer="", $highlight="", $postisread=null, $dummyifcantsee=true, $istracked=null, $return=false) {
f30f46db
RW
679 debugging('forum_print_post() has been deprecated, ' .
680 'please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
2e19ca18
RW
681 global $USER, $CFG, $OUTPUT;
682
683 require_once($CFG->libdir . '/filelib.php');
684
685 // String cache
686 static $str;
687 // This is an extremely hacky way to ensure we only print the 'unread' anchor
688 // the first time we encounter an unread post on a page. Ideally this would
689 // be moved into the caller somehow, and be better testable. But at the time
690 // of dealing with this bug, this static workaround was the most surgical and
691 // it fits together with only printing th unread anchor id once on a given page.
692 static $firstunreadanchorprinted = false;
693
694 $modcontext = context_module::instance($cm->id);
695
696 $post->course = $course->id;
697 $post->forum = $forum->id;
698 $post->message = file_rewrite_pluginfile_urls($post->message, 'pluginfile.php', $modcontext->id, 'mod_forum', 'post', $post->id);
699 if (!empty($CFG->enableplagiarism)) {
700 require_once($CFG->libdir.'/plagiarismlib.php');
701 $post->message .= plagiarism_get_links(array('userid' => $post->userid,
702 'content' => $post->message,
703 'cmid' => $cm->id,
704 'course' => $post->course,
705 'forum' => $post->forum));
706 }
707
708 // caching
709 if (!isset($cm->cache)) {
710 $cm->cache = new stdClass;
711 }
712
713 if (!isset($cm->cache->caps)) {
714 $cm->cache->caps = array();
715 $cm->cache->caps['mod/forum:viewdiscussion'] = has_capability('mod/forum:viewdiscussion', $modcontext);
716 $cm->cache->caps['moodle/site:viewfullnames'] = has_capability('moodle/site:viewfullnames', $modcontext);
717 $cm->cache->caps['mod/forum:editanypost'] = has_capability('mod/forum:editanypost', $modcontext);
718 $cm->cache->caps['mod/forum:splitdiscussions'] = has_capability('mod/forum:splitdiscussions', $modcontext);
719 $cm->cache->caps['mod/forum:deleteownpost'] = has_capability('mod/forum:deleteownpost', $modcontext);
720 $cm->cache->caps['mod/forum:deleteanypost'] = has_capability('mod/forum:deleteanypost', $modcontext);
721 $cm->cache->caps['mod/forum:viewanyrating'] = has_capability('mod/forum:viewanyrating', $modcontext);
722 $cm->cache->caps['mod/forum:exportpost'] = has_capability('mod/forum:exportpost', $modcontext);
723 $cm->cache->caps['mod/forum:exportownpost'] = has_capability('mod/forum:exportownpost', $modcontext);
724 }
725
726 if (!isset($cm->uservisible)) {
727 $cm->uservisible = \core_availability\info_module::is_user_visible($cm, 0, false);
728 }
729
730 if ($istracked && is_null($postisread)) {
731 $postisread = forum_tp_is_post_read($USER->id, $post);
732 }
733
734 if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm, false)) {
735 // Do _not_ check the deleted flag - we need to display a different UI.
736 $output = '';
737 if (!$dummyifcantsee) {
738 if ($return) {
739 return $output;
740 }
741 echo $output;
742 return;
743 }
744
745 $output .= html_writer::start_tag('div', array('class' => 'forumpost clearfix',
746 'aria-label' => get_string('hiddenforumpost', 'forum')));
747 $output .= html_writer::start_tag('header', array('class' => 'row header'));
748 $output .= html_writer::tag('div', '', array('class' => 'left picture', 'role' => 'presentation')); // Picture.
749 if ($post->parent) {
750 $output .= html_writer::start_tag('div', array('class' => 'topic'));
751 } else {
752 $output .= html_writer::start_tag('div', array('class' => 'topic starter'));
753 }
754 $output .= html_writer::tag('div', get_string('forumsubjecthidden','forum'), array('class' => 'subject',
755 'role' => 'header',
756 'id' => ('headp' . $post->id))); // Subject.
757 $authorclasses = array('class' => 'author');
758 $output .= html_writer::tag('address', get_string('forumauthorhidden', 'forum'), $authorclasses); // Author.
759 $output .= html_writer::end_tag('div');
760 $output .= html_writer::end_tag('header'); // Header.
761 $output .= html_writer::start_tag('div', array('class'=>'row'));
762 $output .= html_writer::tag('div', '&nbsp;', array('class'=>'left side')); // Groups
763 $output .= html_writer::tag('div', get_string('forumbodyhidden','forum'), array('class'=>'content')); // Content
764 $output .= html_writer::end_tag('div'); // row
765 $output .= html_writer::end_tag('div'); // forumpost
766
767 if ($return) {
768 return $output;
769 }
770 echo $output;
771 return;
772 }
773
774 if (!empty($post->deleted)) {
775 // Note: Posts marked as deleted are still returned by the above forum_user_can_post because it is required for
776 // nesting of posts.
777 $output = '';
778 if (!$dummyifcantsee) {
779 if ($return) {
780 return $output;
781 }
782 echo $output;
783 return;
784 }
785 $output .= html_writer::start_tag('div', [
786 'class' => 'forumpost clearfix',
787 'aria-label' => get_string('forumbodydeleted', 'forum'),
788 ]);
789
790 $output .= html_writer::start_tag('header', array('class' => 'row header'));
791 $output .= html_writer::tag('div', '', array('class' => 'left picture', 'role' => 'presentation'));
792
793 $classes = ['topic'];
794 if (!empty($post->parent)) {
795 $classes[] = 'starter';
796 }
797 $output .= html_writer::start_tag('div', ['class' => implode(' ', $classes)]);
798
799 // Subject.
800 $output .= html_writer::tag('div', get_string('forumsubjectdeleted', 'forum'), [
801 'class' => 'subject',
802 'role' => 'header',
803 'id' => ('headp' . $post->id)
804 ]);
805
806 // Author.
807 $output .= html_writer::tag('address', '', ['class' => 'author']);
808
809 $output .= html_writer::end_tag('div');
810 $output .= html_writer::end_tag('header'); // End header.
811 $output .= html_writer::start_tag('div', ['class' => 'row']);
812 $output .= html_writer::tag('div', '&nbsp;', ['class' => 'left side']); // Groups.
813 $output .= html_writer::tag('div', get_string('forumbodydeleted', 'forum'), ['class' => 'content']); // Content.
814 $output .= html_writer::end_tag('div'); // End row.
815 $output .= html_writer::end_tag('div'); // End forumpost.
816
817 if ($return) {
818 return $output;
819 }
820 echo $output;
821 return;
822 }
823
824 if (empty($str)) {
825 $str = new stdClass;
826 $str->edit = get_string('edit', 'forum');
827 $str->delete = get_string('delete', 'forum');
828 $str->reply = get_string('reply', 'forum');
829 $str->parent = get_string('parent', 'forum');
830 $str->pruneheading = get_string('pruneheading', 'forum');
831 $str->prune = get_string('prune', 'forum');
832 $str->displaymode = get_user_preferences('forum_displaymode', $CFG->forum_displaymode);
833 $str->markread = get_string('markread', 'forum');
834 $str->markunread = get_string('markunread', 'forum');
835 }
836
837 $discussionlink = new moodle_url('/mod/forum/discuss.php', array('d'=>$post->discussion));
838
839 // Build an object that represents the posting user
840 $postuser = new stdClass;
5e72715e 841 $postuserfields = explode(',', implode(',', \core_user\fields::get_picture_fields()));
2e19ca18
RW
842 $postuser = username_load_fields_from_object($postuser, $post, null, $postuserfields);
843 $postuser->id = $post->userid;
844 $postuser->fullname = fullname($postuser, $cm->cache->caps['moodle/site:viewfullnames']);
845 $postuser->profilelink = new moodle_url('/user/view.php', array('id'=>$post->userid, 'course'=>$course->id));
846
847 // Prepare the groups the posting user belongs to
848 if (isset($cm->cache->usersgroups)) {
849 $groups = array();
850 if (isset($cm->cache->usersgroups[$post->userid])) {
851 foreach ($cm->cache->usersgroups[$post->userid] as $gid) {
852 $groups[$gid] = $cm->cache->groups[$gid];
853 }
854 }
855 } else {
856 $groups = groups_get_all_groups($course->id, $post->userid, $cm->groupingid);
857 }
858
859 // Prepare the attachements for the post, files then images
860 list($attachments, $attachedimages) = forum_print_attachments($post, $cm, 'separateimages');
861
862 // Determine if we need to shorten this post
863 $shortenpost = ($link && (strlen(strip_tags($post->message)) > $CFG->forum_longpost));
864
865 // Prepare an array of commands
866 $commands = array();
867
868 // Add a permalink.
869 $permalink = new moodle_url($discussionlink);
870 $permalink->set_anchor('p' . $post->id);
871 $commands[] = array('url' => $permalink, 'text' => get_string('permalink', 'forum'), 'attributes' => ['rel' => 'bookmark']);
872
873 // SPECIAL CASE: The front page can display a news item post to non-logged in users.
874 // Don't display the mark read / unread controls in this case.
875 if ($istracked && $CFG->forum_usermarksread && isloggedin()) {
876 $url = new moodle_url($discussionlink, array('postid'=>$post->id, 'mark'=>'unread'));
877 $text = $str->markunread;
878 if (!$postisread) {
879 $url->param('mark', 'read');
880 $text = $str->markread;
881 }
882 if ($str->displaymode == FORUM_MODE_THREADED) {
883 $url->param('parent', $post->parent);
884 } else {
885 $url->set_anchor('p'.$post->id);
886 }
887 $commands[] = array('url'=>$url, 'text'=>$text, 'attributes' => ['rel' => 'bookmark']);
888 }
889
890 // Zoom in to the parent specifically
891 if ($post->parent) {
892 $url = new moodle_url($discussionlink);
893 if ($str->displaymode == FORUM_MODE_THREADED) {
894 $url->param('parent', $post->parent);
895 } else {
896 $url->set_anchor('p'.$post->parent);
897 }
898 $commands[] = array('url'=>$url, 'text'=>$str->parent, 'attributes' => ['rel' => 'bookmark']);
899 }
900
901 // Hack for allow to edit news posts those are not displayed yet until they are displayed
902 $age = time() - $post->created;
903 if (!$post->parent && $forum->type == 'news' && $discussion->timestart > time()) {
904 $age = 0;
905 }
906
907 if ($forum->type == 'single' and $discussion->firstpost == $post->id) {
908 if (has_capability('moodle/course:manageactivities', $modcontext)) {
909 // The first post in single simple is the forum description.
910 $commands[] = array('url'=>new moodle_url('/course/modedit.php', array('update'=>$cm->id, 'sesskey'=>sesskey(), 'return'=>1)), 'text'=>$str->edit);
911 }
912 } else if (($ownpost && $age < $CFG->maxeditingtime) || $cm->cache->caps['mod/forum:editanypost']) {
913 $commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('edit'=>$post->id)), 'text'=>$str->edit);
914 }
915
916 if ($cm->cache->caps['mod/forum:splitdiscussions'] && $post->parent && $forum->type != 'single') {
917 $commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('prune'=>$post->id)), 'text'=>$str->prune, 'title'=>$str->pruneheading);
918 }
919
920 if ($forum->type == 'single' and $discussion->firstpost == $post->id) {
921 // Do not allow deleting of first post in single simple type.
922 } else if (($ownpost && $age < $CFG->maxeditingtime && $cm->cache->caps['mod/forum:deleteownpost']) || $cm->cache->caps['mod/forum:deleteanypost']) {
923 $commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('delete'=>$post->id)), 'text'=>$str->delete);
924 }
925
926 if ($reply) {
927 $commands[] = array('url'=>new moodle_url('/mod/forum/post.php#mformforum', array('reply'=>$post->id)), 'text'=>$str->reply);
928 }
929
930 if ($CFG->enableportfolios && ($cm->cache->caps['mod/forum:exportpost'] || ($ownpost && $cm->cache->caps['mod/forum:exportownpost']))) {
931 $p = array('postid' => $post->id);
932 require_once($CFG->libdir.'/portfoliolib.php');
933 $button = new portfolio_add_button();
934 $button->set_callback_options('forum_portfolio_caller', array('postid' => $post->id), 'mod_forum');
935 if (empty($attachments)) {
936 $button->set_formats(PORTFOLIO_FORMAT_PLAINHTML);
937 } else {
938 $button->set_formats(PORTFOLIO_FORMAT_RICHHTML);
939 }
940
941 $porfoliohtml = $button->to_html(PORTFOLIO_ADD_TEXT_LINK);
942 if (!empty($porfoliohtml)) {
943 $commands[] = $porfoliohtml;
944 }
945 }
946 // Finished building commands
947
948
949 // Begin output
950
951 $output = '';
952
953 if ($istracked) {
954 if ($postisread) {
955 $forumpostclass = ' read';
956 } else {
957 $forumpostclass = ' unread';
958 // If this is the first unread post printed then give it an anchor and id of unread.
959 if (!$firstunreadanchorprinted) {
960 $output .= html_writer::tag('a', '', array('id' => 'unread'));
961 $firstunreadanchorprinted = true;
962 }
963 }
964 } else {
965 // ignore trackign status if not tracked or tracked param missing
966 $forumpostclass = '';
967 }
968
969 $topicclass = '';
970 if (empty($post->parent)) {
971 $topicclass = ' firstpost starter';
972 }
973
974 if (!empty($post->lastpost)) {
975 $forumpostclass .= ' lastpost';
976 }
977
978 // Flag to indicate whether we should hide the author or not.
979 $authorhidden = forum_is_author_hidden($post, $forum);
980 $postbyuser = new stdClass;
981 $postbyuser->post = $post->subject;
982 $postbyuser->user = $postuser->fullname;
983 $discussionbyuser = get_string('postbyuser', 'forum', $postbyuser);
984 // Begin forum post.
985 $output .= html_writer::start_div('forumpost clearfix' . $forumpostclass . $topicclass,
986 ['aria-label' => $discussionbyuser]);
987 // Begin header row.
988 $output .= html_writer::start_tag('header', ['class' => 'row header clearfix']);
989
990 // User picture.
991 if (!$authorhidden) {
992 $picture = $OUTPUT->user_picture($postuser, ['courseid' => $course->id]);
993 $output .= html_writer::div($picture, 'left picture', ['role' => 'presentation']);
994 $topicclass = 'topic' . $topicclass;
995 }
996
997 // Begin topic column.
998 $output .= html_writer::start_div($topicclass);
999 $postsubject = $post->subject;
1000 if (empty($post->subjectnoformat)) {
1001 $postsubject = format_string($postsubject);
1002 }
1003 $output .= html_writer::div($postsubject, 'subject', ['role' => 'heading', 'aria-level' => '1', 'id' => ('headp' . $post->id)]);
1004
1005 if ($authorhidden) {
1006 $bytext = userdate_htmltime($post->created);
1007 } else {
1008 $by = new stdClass();
1009 $by->date = userdate_htmltime($post->created);
1010 $by->name = html_writer::link($postuser->profilelink, $postuser->fullname);
1011 $bytext = get_string('bynameondate', 'forum', $by);
1012 }
1013 $bytextoptions = [
1014 'class' => 'author'
1015 ];
1016 $output .= html_writer::tag('address', $bytext, $bytextoptions);
1017 // End topic column.
1018 $output .= html_writer::end_div();
1019
1020 // End header row.
1021 $output .= html_writer::end_tag('header');
1022
1023 // Row with the forum post content.
1024 $output .= html_writer::start_div('row maincontent clearfix');
1025 // Show if author is not hidden or we have groups.
1026 if (!$authorhidden || $groups) {
1027 $output .= html_writer::start_div('left');
1028 $groupoutput = '';
1029 if ($groups) {
1030 $groupoutput = print_group_picture($groups, $course->id, false, true, true);
1031 }
1032 if (empty($groupoutput)) {
1033 $groupoutput = '&nbsp;';
1034 }
1035 $output .= html_writer::div($groupoutput, 'grouppictures');
1036 $output .= html_writer::end_div(); // Left side.
1037 }
1038
1039 $output .= html_writer::start_tag('div', array('class'=>'no-overflow'));
1040 $output .= html_writer::start_tag('div', array('class'=>'content'));
1041
1042 $options = new stdClass;
1043 $options->para = false;
1044 $options->trusted = $post->messagetrust;
1045 $options->context = $modcontext;
1046 if ($shortenpost) {
1047 // Prepare shortened version by filtering the text then shortening it.
1048 $postclass = 'shortenedpost';
1049 $postcontent = format_text($post->message, $post->messageformat, $options);
1050 $postcontent = shorten_text($postcontent, $CFG->forum_shortpost);
1051 $postcontent .= html_writer::link($discussionlink, get_string('readtherest', 'forum'));
1052 $postcontent .= html_writer::tag('div', '('.get_string('numwords', 'moodle', count_words($post->message)).')',
1053 array('class'=>'post-word-count'));
1054 } else {
1055 // Prepare whole post
1056 $postclass = 'fullpost';
1057 $postcontent = format_text($post->message, $post->messageformat, $options, $course->id);
1058 if (!empty($highlight)) {
1059 $postcontent = highlight($highlight, $postcontent);
1060 }
1061 if (!empty($forum->displaywordcount)) {
1062 $postcontent .= html_writer::tag('div', get_string('numwords', 'moodle', count_words($postcontent)),
1063 array('class'=>'post-word-count'));
1064 }
1065 $postcontent .= html_writer::tag('div', $attachedimages, array('class'=>'attachedimages'));
1066 }
1067
1068 if (\core_tag_tag::is_enabled('mod_forum', 'forum_posts')) {
1069 $postcontent .= $OUTPUT->tag_list(core_tag_tag::get_item_tags('mod_forum', 'forum_posts', $post->id), null, 'forum-tags');
1070 }
1071
1072 // Output the post content
1073 $output .= html_writer::tag('div', $postcontent, array('class'=>'posting '.$postclass));
1074 $output .= html_writer::end_tag('div'); // Content
1075 $output .= html_writer::end_tag('div'); // Content mask
1076 $output .= html_writer::end_tag('div'); // Row
1077
1078 $output .= html_writer::start_tag('nav', array('class' => 'row side'));
1079 $output .= html_writer::tag('div','&nbsp;', array('class'=>'left'));
1080 $output .= html_writer::start_tag('div', array('class'=>'options clearfix'));
1081
1082 if (!empty($attachments)) {
1083 $output .= html_writer::tag('div', $attachments, array('class' => 'attachments'));
1084 }
1085
1086 // Output ratings
1087 if (!empty($post->rating)) {
1088 $output .= html_writer::tag('div', $OUTPUT->render($post->rating), array('class'=>'forum-post-rating'));
1089 }
1090
1091 // Output the commands
1092 $commandhtml = array();
1093 foreach ($commands as $command) {
1094 if (is_array($command)) {
1095 $attributes = ['class' => 'nav-item nav-link'];
1096 if (isset($command['attributes'])) {
1097 $attributes = array_merge($attributes, $command['attributes']);
1098 }
1099 $commandhtml[] = html_writer::link($command['url'], $command['text'], $attributes);
1100 } else {
1101 $commandhtml[] = $command;
1102 }
1103 }
1104 $output .= html_writer::tag('div', implode(' ', $commandhtml), array('class' => 'commands nav'));
1105
1106 // Output link to post if required
1107 if ($link) {
1108 if (forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext)) {
1109 $langstring = 'discussthistopic';
1110 } else {
1111 $langstring = 'viewthediscussion';
1112 }
1113 if ($post->replies == 1) {
1114 $replystring = get_string('repliesone', 'forum', $post->replies);
1115 } else {
1116 $replystring = get_string('repliesmany', 'forum', $post->replies);
1117 }
1118 if (!empty($discussion->unread) && $discussion->unread !== '-') {
1119 $replystring .= ' <span class="sep">/</span> <span class="unread">';
1120 $unreadlink = new moodle_url($discussionlink, null, 'unread');
1121 if ($discussion->unread == 1) {
1122 $replystring .= html_writer::link($unreadlink, get_string('unreadpostsone', 'forum'));
1123 } else {
1124 $replystring .= html_writer::link($unreadlink, get_string('unreadpostsnumber', 'forum', $discussion->unread));
1125 }
1126 $replystring .= '</span>';
1127 }
1128
1129 $output .= html_writer::start_tag('div', array('class'=>'link'));
1130 $output .= html_writer::link($discussionlink, get_string($langstring, 'forum'));
1131 $output .= '&nbsp;('.$replystring.')';
1132 $output .= html_writer::end_tag('div'); // link
1133 }
1134
1135 // Output footer if required
1136 if ($footer) {
1137 $output .= html_writer::tag('div', $footer, array('class'=>'footer'));
1138 }
1139
1140 // Close remaining open divs
1141 $output .= html_writer::end_tag('div'); // content
1142 $output .= html_writer::end_tag('nav'); // row
1143 $output .= html_writer::end_tag('div'); // forumpost
1144
1145 // Mark the forum post as read if required
1146 if ($istracked && !$CFG->forum_usermarksread && !$postisread) {
1147 forum_tp_mark_post_read($USER->id, $post);
1148 }
1149
1150 if ($return) {
1151 return $output;
1152 }
1153 echo $output;
1154 return;
1155}
1156
1157/**
1158 * @global object
1159 * @global object
1160 * @uses FORUM_MODE_FLATNEWEST
1161 * @param object $course
1162 * @param object $cm
1163 * @param object $forum
1164 * @param object $discussion
1165 * @param object $post
1166 * @param object $mode
1167 * @param bool $reply
1168 * @param bool $forumtracked
1169 * @param array $posts
1170 * @return void
1171 * @deprecated since Moodle 3.7
1172 */
1173function forum_print_posts_flat($course, &$cm, $forum, $discussion, $post, $mode, $reply, $forumtracked, $posts) {
f30f46db
RW
1174 debugging('forum_print_posts_flat() has been deprecated, ' .
1175 'please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
2e19ca18
RW
1176 global $USER, $CFG;
1177
1178 $link = false;
1179
1180 foreach ($posts as $post) {
1181 if (!$post->parent) {
1182 continue;
1183 }
1184 $post->subject = format_string($post->subject);
1185 $ownpost = ($USER->id == $post->userid);
1186
1187 $postread = !empty($post->postread);
1188
1189 forum_print_post_start($post);
1190 forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
1191 '', '', $postread, true, $forumtracked);
1192 forum_print_post_end($post);
1193 }
1194}
1195
1196/**
1197 * @todo Document this function
1198 *
1199 * @global object
1200 * @global object
1201 * @uses CONTEXT_MODULE
1202 * @return void
1203 * @deprecated since Moodle 3.7
1204 */
1205function forum_print_posts_threaded($course, &$cm, $forum, $discussion, $parent, $depth, $reply, $forumtracked, $posts) {
f30f46db
RW
1206 debugging('forum_print_posts_threaded() has been deprecated, ' .
1207 'please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
2e19ca18
RW
1208 global $USER, $CFG;
1209
1210 $link = false;
1211
1212 if (!empty($posts[$parent->id]->children)) {
1213 $posts = $posts[$parent->id]->children;
1214
1215 $modcontext = context_module::instance($cm->id);
1216 $canviewfullnames = has_capability('moodle/site:viewfullnames', $modcontext);
1217
1218 foreach ($posts as $post) {
1219
1220 echo '<div class="indent">';
1221 if ($depth > 0) {
1222 $ownpost = ($USER->id == $post->userid);
1223 $post->subject = format_string($post->subject);
1224
1225 $postread = !empty($post->postread);
1226
1227 forum_print_post_start($post);
1228 forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
1229 '', '', $postread, true, $forumtracked);
1230 forum_print_post_end($post);
1231 } else {
1232 if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm, true)) {
1233 if (forum_user_can_see_post($forum, $discussion, $post, null, $cm, false)) {
1234 // This post has been deleted but still exists and may have children.
1235 $subject = get_string('privacy:request:delete:post:subject', 'mod_forum');
1236 $byline = '';
1237 } else {
1238 // The user can't see this post at all.
1239 echo "</div>\n";
1240 continue;
1241 }
1242 } else {
1243 $by = new stdClass();
1244 $by->name = fullname($post, $canviewfullnames);
1245 $by->date = userdate_htmltime($post->modified);
1246 $byline = ' ' . get_string("bynameondate", "forum", $by);
1247 $subject = format_string($post->subject, true);
1248 }
1249
1250 if ($forumtracked) {
1251 if (!empty($post->postread)) {
1252 $style = '<span class="forumthread read">';
1253 } else {
1254 $style = '<span class="forumthread unread">';
1255 }
1256 } else {
1257 $style = '<span class="forumthread">';
1258 }
1259
1260 echo $style;
1261 echo "<a name='{$post->id}'></a>";
1262 echo html_writer::link(new moodle_url('/mod/forum/discuss.php', [
1263 'd' => $post->discussion,
1264 'parent' => $post->id,
1265 ]), $subject);
1266 echo $byline;
1267 echo "</span>";
1268 }
1269
1270 forum_print_posts_threaded($course, $cm, $forum, $discussion, $post, $depth-1, $reply, $forumtracked, $posts);
1271 echo "</div>\n";
1272 }
1273 }
1274}
1275
1276/**
1277 * @todo Document this function
1278 * @global object
1279 * @global object
1280 * @return void
1281 * @deprecated since Moodle 3.7
1282 */
1283function forum_print_posts_nested($course, &$cm, $forum, $discussion, $parent, $reply, $forumtracked, $posts) {
f30f46db
RW
1284 debugging('forum_print_posts_nested() has been deprecated, ' .
1285 'please use \mod_forum\local\renderers\posts instead.', DEBUG_DEVELOPER);
2e19ca18
RW
1286 global $USER, $CFG;
1287
1288 $link = false;
1289
1290 if (!empty($posts[$parent->id]->children)) {
1291 $posts = $posts[$parent->id]->children;
1292
1293 foreach ($posts as $post) {
1294
1295 echo '<div class="indent">';
1296 if (!isloggedin()) {
1297 $ownpost = false;
1298 } else {
1299 $ownpost = ($USER->id == $post->userid);
1300 }
1301
1302 $post->subject = format_string($post->subject);
1303 $postread = !empty($post->postread);
1304
1305 forum_print_post_start($post);
1306 forum_print_post($post, $discussion, $forum, $cm, $course, $ownpost, $reply, $link,
1307 '', '', $postread, true, $forumtracked);
1308 forum_print_posts_nested($course, $cm, $forum, $discussion, $post, $reply, $forumtracked, $posts);
1309 forum_print_post_end($post);
1310 echo "</div>\n";
1311 }
1312 }
1313}
a79c2c92
AN
1314
1315/**
1316 * Prints the discussion view screen for a forum.
1317 *
1318 * @param object $course The current course object.
1319 * @param object $forum Forum to be printed.
1320 * @param int $maxdiscussions
1321 * @param string $displayformat The display format to use (optional).
1322 * @param string $sort Sort arguments for database query (optional).
1323 * @param int $currentgroup
1324 * @param int $groupmode Group mode of the forum (optional).
1325 * @param int $page Page mode, page to display (optional).
1326 * @param int $perpage The maximum number of discussions per page(optional)
1327 * @param stdClass $cm
1328 * @deprecated since Moodle 3.7
1329 */
1330function forum_print_latest_discussions($course, $forum, $maxdiscussions = -1, $displayformat = 'plain', $sort = '',
1331 $currentgroup = -1, $groupmode = -1, $page = -1, $perpage = 100, $cm = null) {
1332 debugging('forum_print_latest_discussions has been deprecated.', DEBUG_DEVELOPER);
1333 global $CFG, $USER, $OUTPUT;
1334
1335 require_once($CFG->dirroot . '/course/lib.php');
1336
1337 if (!$cm) {
1338 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
1339 print_error('invalidcoursemodule');
1340 }
1341 }
1342 $context = context_module::instance($cm->id);
1343
1344 if (empty($sort)) {
1345 $sort = forum_get_default_sort_order();
1346 }
1347
1348 $olddiscussionlink = false;
1349
1350 // Sort out some defaults.
1351 if ($perpage <= 0) {
1352 $perpage = 0;
1353 $page = -1;
1354 }
1355
1356 if ($maxdiscussions == 0) {
1357 // All discussions - backwards compatibility.
1358 $page = -1;
1359 $perpage = 0;
1360 if ($displayformat == 'plain') {
1361 $displayformat = 'header'; // Abbreviate display by default.
1362 }
1363
1364 } else if ($maxdiscussions > 0) {
1365 $page = -1;
1366 $perpage = $maxdiscussions;
1367 }
1368
1369 $fullpost = false;
1370 if ($displayformat == 'plain') {
1371 $fullpost = true;
1372 }
1373
1374 // Decide if current user is allowed to see ALL the current discussions or not.
1375 // First check the group stuff.
1376 if ($currentgroup == -1 or $groupmode == -1) {
1377 $groupmode = groups_get_activity_groupmode($cm, $course);
1378 $currentgroup = groups_get_activity_group($cm);
1379 }
1380
1381 // Cache.
1382 $groups = array();
1383
1384 // If the user can post discussions, then this is a good place to put the
1385 // button for it. We do not show the button if we are showing site news
1386 // and the current user is a guest.
1387
1388 $canstart = forum_user_can_post_discussion($forum, $currentgroup, $groupmode, $cm, $context);
1389 if (!$canstart and $forum->type !== 'news') {
1390 if (isguestuser() or !isloggedin()) {
1391 $canstart = true;
1392 }
1393 if (!is_enrolled($context) and !is_viewing($context)) {
1394 // Allow guests and not-logged-in to see the button - they are prompted to log in after clicking the link
1395 // normal users with temporary guest access see this button too, they are asked to enrol instead
1396 // do not show the button to users with suspended enrolments here.
1397 $canstart = enrol_selfenrol_available($course->id);
1398 }
1399 }
1400
1401 if ($canstart) {
1402 switch ($forum->type) {
1403 case 'news':
1404 case 'blog':
1405 $buttonadd = get_string('addanewtopic', 'forum');
1406 break;
1407 case 'qanda':
1408 $buttonadd = get_string('addanewquestion', 'forum');
1409 break;
1410 default:
1411 $buttonadd = get_string('addanewdiscussion', 'forum');
1412 break;
1413 }
1414 $button = new single_button(new moodle_url('/mod/forum/post.php', ['forum' => $forum->id]), $buttonadd, 'get');
1415 $button->class = 'singlebutton forumaddnew';
1416 $button->formid = 'newdiscussionform';
1417 echo $OUTPUT->render($button);
1418
1419 } else if (isguestuser() or !isloggedin() or $forum->type == 'news' or
1420 $forum->type == 'qanda' and !has_capability('mod/forum:addquestion', $context) or
1421 $forum->type != 'qanda' and !has_capability('mod/forum:startdiscussion', $context)) {
1422 // No button and no info.
1423 $ignore = true;
1424 } else if ($groupmode and !has_capability('moodle/site:accessallgroups', $context)) {
1425 // Inform users why they can not post new discussion.
1426 if (!$currentgroup) {
1427 if (!has_capability('mod/forum:canposttomygroups', $context)) {
1428 echo $OUTPUT->notification(get_string('cannotadddiscussiongroup', 'forum'));
1429 } else {
1430 echo $OUTPUT->notification(get_string('cannotadddiscussionall', 'forum'));
1431 }
1432 } else if (!groups_is_member($currentgroup)) {
1433 echo $OUTPUT->notification(get_string('cannotadddiscussion', 'forum'));
1434 }
1435 }
1436
1437 // Get all the recent discussions we're allowed to see.
1438
1439 $getuserlastmodified = ($displayformat == 'header');
1440
1441 $discussions = forum_get_discussions($cm, $sort, $fullpost, null, $maxdiscussions, $getuserlastmodified, $page, $perpage);
bc4c7337 1442 if (!$discussions) {
a79c2c92
AN
1443 echo '<div class="forumnodiscuss">';
1444 if ($forum->type == 'news') {
1445 echo '('.get_string('nonews', 'forum').')';
1446 } else if ($forum->type == 'qanda') {
1447 echo '('.get_string('noquestions', 'forum').')';
1448 } else {
1449 echo '('.get_string('nodiscussions', 'forum').')';
1450 }
1451 echo "</div>\n";
1452 return;
1453 }
1454
1455 $canseeprivatereplies = has_capability('mod/forum:readprivatereplies', $context);
1456 // If we want paging.
1457 if ($page != -1) {
1458 // Get the number of discussions found.
1459 $numdiscussions = forum_get_discussions_count($cm);
1460
1461 // Show the paging bar.
1462 echo $OUTPUT->paging_bar($numdiscussions, $page, $perpage, "view.php?f=$forum->id");
1463 if ($numdiscussions > 1000) {
1464 // Saves some memory on sites with very large forums.
1465 $replies = forum_count_discussion_replies($forum->id, $sort, $maxdiscussions, $page, $perpage, $canseeprivatereplies);
1466 } else {
1467 $replies = forum_count_discussion_replies($forum->id, "", -1, -1, 0, $canseeprivatereplies);
1468 }
1469
1470 } else {
1471 $replies = forum_count_discussion_replies($forum->id, "", -1, -1, 0, $canseeprivatereplies);
1472
1473 if ($maxdiscussions > 0 and $maxdiscussions <= count($discussions)) {
1474 $olddiscussionlink = true;
1475 }
1476 }
1477
1478 $canviewparticipants = course_can_view_participants($context);
1479 $canviewhiddentimedposts = has_capability('mod/forum:viewhiddentimedposts', $context);
1480
1481 $strdatestring = get_string('strftimerecentfull');
1482
1483 // Check if the forum is tracked.
1484 if ($cantrack = forum_tp_can_track_forums($forum)) {
1485 $forumtracked = forum_tp_is_tracked($forum);
1486 } else {
1487 $forumtracked = false;
1488 }
1489
1490 if ($forumtracked) {
1491 $unreads = forum_get_discussions_unread($cm);
1492 } else {
1493 $unreads = array();
1494 }
1495
1496 if ($displayformat == 'header') {
1497 echo '<table cellspacing="0" class="forumheaderlist">';
1498 echo '<thead class="text-left">';
1499 echo '<tr>';
1500 echo '<th class="header topic" scope="col">'.get_string('discussion', 'forum').'</th>';
1501 echo '<th class="header author" scope="col">'.get_string('startedby', 'forum').'</th>';
1502 if ($groupmode > 0) {
1503 echo '<th class="header group" scope="col">'.get_string('group').'</th>';
1504 }
1505 if (has_capability('mod/forum:viewdiscussion', $context)) {
1506 echo '<th class="header replies" scope="col">'.get_string('replies', 'forum').'</th>';
1507 // If the forum can be tracked, display the unread column.
1508 if ($cantrack) {
1509 echo '<th class="header replies" scope="col">'.get_string('unread', 'forum');
1510 if ($forumtracked) {
1511 echo '<a title="'.get_string('markallread', 'forum').
1512 '" href="'.$CFG->wwwroot.'/mod/forum/markposts.php?f='.
1513 $forum->id.'&amp;mark=read&amp;return=/mod/forum/view.php&amp;sesskey=' . sesskey() . '">'.
1514 $OUTPUT->pix_icon('t/markasread', get_string('markallread', 'forum')) . '</a>';
1515 }
1516 echo '</th>';
1517 }
1518 }
1519 echo '<th class="header lastpost" scope="col">'.get_string('lastpost', 'forum').'</th>';
1520 if ((!is_guest($context, $USER) && isloggedin()) && has_capability('mod/forum:viewdiscussion', $context)) {
1521 if (\mod_forum\subscriptions::is_subscribable($forum)) {
1522 echo '<th class="header discussionsubscription" scope="col">';
1523 echo forum_get_discussion_subscription_icon_preloaders();
1524 echo '</th>';
1525 }
1526 }
1527 echo '</tr>';
1528 echo '</thead>';
1529 echo '<tbody>';
1530 }
1531
1532 foreach ($discussions as $discussion) {
1533 if ($forum->type == 'qanda' && !has_capability('mod/forum:viewqandawithoutposting', $context) &&
1534 !forum_user_has_posted($forum->id, $discussion->discussion, $USER->id)) {
1535 $canviewparticipants = false;
1536 }
1537
1538 if (!empty($replies[$discussion->discussion])) {
1539 $discussion->replies = $replies[$discussion->discussion]->replies;
1540 $discussion->lastpostid = $replies[$discussion->discussion]->lastpostid;
1541 } else {
1542 $discussion->replies = 0;
1543 }
1544
1545 // SPECIAL CASE: The front page can display a news item post to non-logged in users.
1546 // All posts are read in this case.
1547 if (!$forumtracked) {
1548 $discussion->unread = '-';
1549 } else if (empty($USER)) {
1550 $discussion->unread = 0;
1551 } else {
1552 if (empty($unreads[$discussion->discussion])) {
1553 $discussion->unread = 0;
1554 } else {
1555 $discussion->unread = $unreads[$discussion->discussion];
1556 }
1557 }
1558
1559 if (isloggedin()) {
1560 $ownpost = ($discussion->userid == $USER->id);
1561 } else {
1562 $ownpost = false;
1563 }
1564 // Use discussion name instead of subject of first post.
1565 $discussion->subject = $discussion->name;
1566
1567 switch ($displayformat) {
1568 case 'header':
1569 if ($groupmode > 0) {
1570 if (isset($groups[$discussion->groupid])) {
1571 $group = $groups[$discussion->groupid];
1572 } else {
1573 $group = $groups[$discussion->groupid] = groups_get_group($discussion->groupid);
1574 }
1575 } else {
1576 $group = -1;
1577 }
1578 forum_print_discussion_header($discussion, $forum, $group, $strdatestring, $cantrack, $forumtracked,
1579 $canviewparticipants, $context, $canviewhiddentimedposts);
1580 break;
1581 default:
1582 $link = false;
1583
1584 if ($discussion->replies) {
1585 $link = true;
1586 } else {
1587 $modcontext = context_module::instance($cm->id);
1588 $link = forum_user_can_see_discussion($forum, $discussion, $modcontext, $USER);
1589 }
1590
1591 $discussion->forum = $forum->id;
1592
1593 forum_print_post_start($discussion);
1594 forum_print_post($discussion, $discussion, $forum, $cm, $course, $ownpost, 0, $link, false,
1595 '', null, true, $forumtracked);
1596 forum_print_post_end($discussion);
1597 break;
1598 }
1599 }
1600
1601 if ($displayformat == "header") {
1602 echo '</tbody>';
1603 echo '</table>';
1604 }
1605
1606 if ($olddiscussionlink) {
1607 if ($forum->type == 'news') {
1608 $strolder = get_string('oldertopics', 'forum');
1609 } else {
1610 $strolder = get_string('olderdiscussions', 'forum');
1611 }
1612 echo '<div class="forumolddiscuss">';
1613 echo '<a href="'.$CFG->wwwroot.'/mod/forum/view.php?f='.$forum->id.'&amp;showall=1">';
1614 echo $strolder.'</a> ...</div>';
1615 }
1616
1617 if ($page != -1) {
1618 // Show the paging bar.
1619 echo $OUTPUT->paging_bar($numdiscussions, $page, $perpage, "view.php?f=$forum->id");
1620 }
1621}
15dc885a
AN
1622
1623/**
1624 * Count the number of replies to the specified post.
1625 *
1626 * @param object $post
1627 * @param bool $children
1628 * @return int
1629 * @deprecated since Moodle 3.7
74ee34fd 1630 * @todo MDL-65252 This will be removed in Moodle 3.11
15dc885a
AN
1631 */
1632function forum_count_replies($post, $children = true) {
1633 global $USER;
1634 debugging('forum_count_replies has been deprecated. Please use the Post vault instead.', DEBUG_DEVELOPER);
1635
1636 if (!$children) {
1637 return $DB->count_records('forum_posts', array('parent' => $post->id));
1638 }
1639
1640 $entityfactory = mod_forum\local\container::get_entity_factory();
1641 $postentity = $entityfactory->get_post_from_stdclass($post);
1642
1643 $vaultfactory = mod_forum\local\container::get_vault_factory();
1644 $postvault = $vaultfactory->get_post_vault();
1645
1646 return $postvault->get_reply_count_for_post_id_in_discussion_id(
1647 $USER,
1648 $postentity->get_id(),
1649 $postentity->get_discussion_id(),
1650 true
1651 );
1652}
c0375ba7
AA
1653
1654/**
1655 * @deprecated since Moodle 3.8
1656 */
1657function forum_scale_used() {
1658 throw new coding_exception('forum_scale_used() can not be used anymore. Plugins can implement ' .
1659 '<modname>_scale_used_anywhere, all implementations of <modname>_scale_used are now ignored');
1660}
92b229c5
AN
1661
1662/**
1663 * Return grade for given user or all users.
1664 *
1665 * @deprecated since Moodle 3.8
1666 * @param object $forum
1667 * @param int $userid optional user id, 0 means all users
1668 * @return array array of grades, false if none
1669 */
1670function forum_get_user_grades($forum, $userid = 0) {
1671 global $CFG;
1672
1673 require_once($CFG->dirroot.'/rating/lib.php');
1674
1675 $ratingoptions = (object) [
1676 'component' => 'mod_forum',
1677 'ratingarea' => 'post',
1678 'contextid' => $contextid,
1679
1680 'modulename' => 'forum',
1681 'moduleid ' => $forum->id,
1682 'userid' => $userid,
1683 'aggregationmethod' => $forum->assessed,
1684 'scaleid' => $forum->scale,
1685 'itemtable' => 'forum_posts',
1686 'itemtableusercolumn' => 'userid',
1687 ];
1688
1689 $rm = new rating_manager();
1690 return $rm->get_user_grades($ratingoptions);
1691}
c9fa4f9c
JP
1692
1693/**
1694 * Obtains the automatic completion state for this forum based on any conditions
1695 * in forum settings.
1696 *
1697 * @deprecated since Moodle 3.11
1698 * @todo MDL-71196 Final deprecation in Moodle 4.3
1699 * @see \mod_forum\completion\custom_completion
1700 * @global object
1701 * @global object
1702 * @param object $course Course
1703 * @param object $cm Course-module
1704 * @param int $userid User ID
1705 * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
1706 * @return bool True if completed, false if not. (If no conditions, then return
1707 * value depends on comparison type)
1708 */
1709function forum_get_completion_state($course, $cm, $userid, $type) {
1710 global $DB;
1711
1712 // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state().
1713
1714 // Get forum details.
1715 if (!($forum = $DB->get_record('forum', array('id' => $cm->instance)))) {
1716 throw new Exception("Can't find forum {$cm->instance}");
1717 }
1718
1719 $result = $type; // Default return value.
1720
1721 $postcountparams = array('userid' => $userid, 'forumid' => $forum->id);
1722 $postcountsql = "
1723SELECT
1724 COUNT(1)
1725FROM
1726 {forum_posts} fp
1727 INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id
1728WHERE
1729 fp.userid=:userid AND fd.forum=:forumid";
1730
1731 if ($forum->completiondiscussions) {
1732 $value = $forum->completiondiscussions <=
1733 $DB->count_records('forum_discussions', array('forum' => $forum->id, 'userid' => $userid));
1734 if ($type == COMPLETION_AND) {
1735 $result = $result && $value;
1736 } else {
1737 $result = $result || $value;
1738 }
1739 }
1740 if ($forum->completionreplies) {
1741 $value = $forum->completionreplies <=
1742 $DB->get_field_sql($postcountsql . ' AND fp.parent<>0', $postcountparams);
1743 if ($type == COMPLETION_AND) {
1744 $result = $result && $value;
1745 } else {
1746 $result = $result || $value;
1747 }
1748 }
1749 if ($forum->completionposts) {
1750 $value = $forum->completionposts <= $DB->get_field_sql($postcountsql, $postcountparams);
1751 if ($type == COMPLETION_AND) {
1752 $result = $result && $value;
1753 } else {
1754 $result = $result || $value;
1755 }
1756 }
1757
1758 return $result;
1759}