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 * Edit and save a new post to a discussion 19 * 20 * @package mod_forum 21 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25require_once('../../config.php'); 26require_once('lib.php'); 27require_once($CFG->libdir.'/completionlib.php'); 28 29$reply = optional_param('reply', 0, PARAM_INT); 30$forum = optional_param('forum', 0, PARAM_INT); 31$edit = optional_param('edit', 0, PARAM_INT); 32$delete = optional_param('delete', 0, PARAM_INT); 33$prune = optional_param('prune', 0, PARAM_INT); 34$name = optional_param('name', '', PARAM_CLEAN); 35$confirm = optional_param('confirm', 0, PARAM_INT); 36$groupid = optional_param('groupid', null, PARAM_INT); 37$subject = optional_param('subject', '', PARAM_TEXT); 38 39// Values posted via the inpage reply form. 40$prefilledpost = optional_param('post', '', PARAM_TEXT); 41$prefilledpostformat = optional_param('postformat', FORMAT_MOODLE, PARAM_INT); 42$prefilledprivatereply = optional_param('privatereply', false, PARAM_BOOL); 43 44$PAGE->set_url('/mod/forum/post.php', array( 45 'reply' => $reply, 46 'forum' => $forum, 47 'edit' => $edit, 48 'delete' => $delete, 49 'prune' => $prune, 50 'name' => $name, 51 'confirm' => $confirm, 52 'groupid' => $groupid, 53)); 54// These page_params will be passed as hidden variables later in the form. 55$pageparams = array('reply' => $reply, 'forum' => $forum, 'edit' => $edit); 56 57$sitecontext = context_system::instance(); 58 59$entityfactory = mod_forum\local\container::get_entity_factory(); 60$vaultfactory = mod_forum\local\container::get_vault_factory(); 61$managerfactory = mod_forum\local\container::get_manager_factory(); 62$legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory(); 63$urlfactory = mod_forum\local\container::get_url_factory(); 64 65$forumvault = $vaultfactory->get_forum_vault(); 66$forumdatamapper = $legacydatamapperfactory->get_forum_data_mapper(); 67 68$discussionvault = $vaultfactory->get_discussion_vault(); 69$discussiondatamapper = $legacydatamapperfactory->get_discussion_data_mapper(); 70 71$postvault = $vaultfactory->get_post_vault(); 72$postdatamapper = $legacydatamapperfactory->get_post_data_mapper(); 73 74if (!isloggedin() or isguestuser()) { 75 if (!isloggedin() and !get_local_referer()) { 76 // No referer+not logged in - probably coming in via email See MDL-9052. 77 require_login(); 78 } 79 80 if (!empty($forum)) { 81 // User is starting a new discussion in a forum. 82 $forumentity = $forumvault->get_from_id($forum); 83 if (empty($forumentity)) { 84 print_error('invalidforumid', 'forum'); 85 } 86 } else if (!empty($reply)) { 87 // User is writing a new reply. 88 $forumentity = $forumvault->get_from_post_id($reply); 89 if (empty($forumentity)) { 90 print_error('invalidparentpostid', 'forum'); 91 } 92 } 93 94 $forum = $forumdatamapper->to_legacy_object($forumentity); 95 $modcontext = $forumentity->get_context(); 96 $course = $forumentity->get_course_record(); 97 if (!$cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) { 98 print_error("invalidcoursemodule"); 99 } 100 101 $PAGE->set_cm($cm, $course, $forum); 102 $PAGE->set_context($modcontext); 103 $PAGE->set_title($course->shortname); 104 $PAGE->set_heading($course->fullname); 105 $referer = get_local_referer(false); 106 107 echo $OUTPUT->header(); 108 echo $OUTPUT->confirm(get_string('noguestpost', 'forum').'<br /><br />'.get_string('liketologin'), get_login_url(), $referer); 109 echo $OUTPUT->footer(); 110 exit; 111} 112 113require_login(0, false); // Script is useless unless they're logged in. 114 115$canreplyprivately = false; 116 117if (!empty($forum)) { 118 // User is starting a new discussion in a forum. 119 $forumentity = $forumvault->get_from_id($forum); 120 if (empty($forumentity)) { 121 print_error('invalidforumid', 'forum'); 122 } 123 124 $capabilitymanager = $managerfactory->get_capability_manager($forumentity); 125 $forum = $forumdatamapper->to_legacy_object($forumentity); 126 $course = $forumentity->get_course_record(); 127 if (!$cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) { 128 print_error("invalidcoursemodule"); 129 } 130 131 // Retrieve the contexts. 132 $modcontext = $forumentity->get_context(); 133 $coursecontext = context_course::instance($course->id); 134 135 if ($forumentity->is_in_group_mode() && null === $groupid) { 136 $groupid = groups_get_activity_group($cm); 137 } 138 139 if (!$capabilitymanager->can_create_discussions($USER, $groupid)) { 140 if (!isguestuser()) { 141 if (!is_enrolled($coursecontext)) { 142 if (enrol_selfenrol_available($course->id)) { 143 $SESSION->wantsurl = qualified_me(); 144 $SESSION->enrolcancel = get_local_referer(false); 145 redirect(new moodle_url('/enrol/index.php', array('id' => $course->id, 146 'returnurl' => '/mod/forum/view.php?f=' . $forum->id)), 147 get_string('youneedtoenrol')); 148 } 149 } 150 } 151 print_error('nopostforum', 'forum'); 152 } 153 154 if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $modcontext)) { 155 redirect( 156 $urlfactory->get_course_url_from_forum($forumentity), 157 get_string('activityiscurrentlyhidden'), 158 null, 159 \core\output\notification::NOTIFY_ERROR 160 ); 161 } 162 163 $SESSION->fromurl = get_local_referer(false); 164 165 // Load up the $post variable. 166 167 $post = new stdClass(); 168 $post->course = $course->id; 169 $post->forum = $forum->id; 170 $post->discussion = 0; // Ie discussion # not defined yet. 171 $post->parent = 0; 172 $post->subject = $subject; 173 $post->userid = $USER->id; 174 $post->message = $prefilledpost; 175 $post->messageformat = editors_get_preferred_format(); 176 $post->messagetrust = 0; 177 $post->groupid = $groupid; 178 179 // Unsetting this will allow the correct return URL to be calculated later. 180 unset($SESSION->fromdiscussion); 181 182} else if (!empty($reply)) { 183 // User is writing a new reply. 184 185 $parententity = $postvault->get_from_id($reply); 186 if (empty($parententity)) { 187 print_error('invalidparentpostid', 'forum'); 188 } 189 190 $discussionentity = $discussionvault->get_from_id($parententity->get_discussion_id()); 191 if (empty($discussionentity)) { 192 print_error('notpartofdiscussion', 'forum'); 193 } 194 195 $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id()); 196 if (empty($forumentity)) { 197 print_error('invalidforumid', 'forum'); 198 } 199 200 $capabilitymanager = $managerfactory->get_capability_manager($forumentity); 201 $parent = $postdatamapper->to_legacy_object($parententity); 202 $discussion = $discussiondatamapper->to_legacy_object($discussionentity); 203 $forum = $forumdatamapper->to_legacy_object($forumentity); 204 $course = $forumentity->get_course_record(); 205 $modcontext = $forumentity->get_context(); 206 $coursecontext = context_course::instance($course->id); 207 208 if (!$cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) { 209 print_error('invalidcoursemodule'); 210 } 211 212 // Ensure lang, theme, etc. is set up properly. MDL-6926. 213 $PAGE->set_cm($cm, $course, $forum); 214 215 if (!$capabilitymanager->can_reply_to_post($USER, $discussionentity, $parententity)) { 216 if (!isguestuser()) { 217 if (!is_enrolled($coursecontext)) { // User is a guest here! 218 $SESSION->wantsurl = qualified_me(); 219 $SESSION->enrolcancel = get_local_referer(false); 220 redirect(new moodle_url('/enrol/index.php', array('id' => $course->id, 221 'returnurl' => '/mod/forum/view.php?f=' . $forum->id)), 222 get_string('youneedtoenrol')); 223 } 224 225 // The forum has been locked. Just redirect back to the discussion page. 226 if (forum_discussion_is_locked($forum, $discussion)) { 227 redirect(new moodle_url('/mod/forum/discuss.php', array('d' => $discussion->id))); 228 } 229 } 230 print_error('nopostforum', 'forum'); 231 } 232 233 // Make sure user can post here. 234 if (isset($cm->groupmode) && empty($course->groupmodeforce)) { 235 $groupmode = $cm->groupmode; 236 } else { 237 $groupmode = $course->groupmode; 238 } 239 if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $modcontext)) { 240 if ($discussion->groupid == -1) { 241 print_error('nopostforum', 'forum'); 242 } else { 243 if (!groups_is_member($discussion->groupid)) { 244 print_error('nopostforum', 'forum'); 245 } 246 } 247 } 248 249 if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $modcontext)) { 250 print_error("activityiscurrentlyhidden"); 251 } 252 253 if ($parententity->is_private_reply()) { 254 print_error('cannotreplytoprivatereply', 'forum'); 255 } 256 257 // We always are going to honor the preferred format. We are creating a new post. 258 $preferredformat = editors_get_preferred_format(); 259 260 // Only if there are prefilled contents coming. 261 if (!empty($prefilledpost)) { 262 // If the prefilled post is not HTML and the preferred format is HTML, convert to it. 263 if ($prefilledpostformat != FORMAT_HTML and $preferredformat == FORMAT_HTML) { 264 $prefilledpost = format_text($prefilledpost, $prefilledpostformat, ['context' => $modcontext]); 265 } 266 } 267 268 // Load up the $post variable. 269 $post = new stdClass(); 270 $post->course = $course->id; 271 $post->forum = $forum->id; 272 $post->discussion = $parent->discussion; 273 $post->parent = $parent->id; 274 $post->subject = $subject ? $subject : $parent->subject; 275 $post->userid = $USER->id; 276 $post->parentpostauthor = $parent->userid; 277 $post->message = $prefilledpost; 278 $post->messageformat = $preferredformat; 279 $post->isprivatereply = $prefilledprivatereply; 280 $canreplyprivately = $capabilitymanager->can_reply_privately_to_post($USER, $parententity); 281 282 $post->groupid = ($discussion->groupid == -1) ? 0 : $discussion->groupid; 283 284 $strre = get_string('re', 'forum'); 285 if (!(substr($post->subject, 0, strlen($strre)) == $strre)) { 286 $post->subject = $strre.' '.$post->subject; 287 } 288 289 // Unsetting this will allow the correct return URL to be calculated later. 290 unset($SESSION->fromdiscussion); 291 292} else if (!empty($edit)) { 293 // User is editing their own post. 294 295 $postentity = $postvault->get_from_id($edit); 296 if (empty($postentity)) { 297 print_error('invalidpostid', 'forum'); 298 } 299 if ($postentity->has_parent()) { 300 $parententity = $postvault->get_from_id($postentity->get_parent_id()); 301 $parent = $postdatamapper->to_legacy_object($parententity); 302 } 303 304 $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id()); 305 if (empty($discussionentity)) { 306 print_error('notpartofdiscussion', 'forum'); 307 } 308 309 $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id()); 310 if (empty($forumentity)) { 311 print_error('invalidforumid', 'forum'); 312 } 313 314 $capabilitymanager = $managerfactory->get_capability_manager($forumentity); 315 $post = $postdatamapper->to_legacy_object($postentity); 316 $discussion = $discussiondatamapper->to_legacy_object($discussionentity); 317 $forum = $forumdatamapper->to_legacy_object($forumentity); 318 $course = $forumentity->get_course_record(); 319 $modcontext = $forumentity->get_context(); 320 $coursecontext = context_course::instance($course->id); 321 322 if (!$cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) { 323 print_error('invalidcoursemodule'); 324 } 325 326 $PAGE->set_cm($cm, $course, $forum); 327 328 if (!($forum->type == 'news' && !$post->parent && $discussion->timestart > time())) { 329 if (((time() - $post->created) > $CFG->maxeditingtime) and 330 !has_capability('mod/forum:editanypost', $modcontext)) { 331 print_error('maxtimehaspassed', 'forum', '', format_time($CFG->maxeditingtime)); 332 } 333 } 334 if (($post->userid <> $USER->id) and 335 !has_capability('mod/forum:editanypost', $modcontext)) { 336 print_error('cannoteditposts', 'forum'); 337 } 338 339 // Load up the $post variable. 340 $post->edit = $edit; 341 $post->course = $course->id; 342 $post->forum = $forum->id; 343 $post->groupid = ($discussion->groupid == -1) ? 0 : $discussion->groupid; 344 if ($postentity->has_parent()) { 345 $canreplyprivately = forum_user_can_reply_privately($modcontext, $parent); 346 } 347 348 $post = trusttext_pre_edit($post, 'message', $modcontext); 349 350 // Unsetting this will allow the correct return URL to be calculated later. 351 unset($SESSION->fromdiscussion); 352 353} else if (!empty($delete)) { 354 // User is deleting a post. 355 356 $postentity = $postvault->get_from_id($delete); 357 if (empty($postentity)) { 358 print_error('invalidpostid', 'forum'); 359 } 360 361 $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id()); 362 if (empty($discussionentity)) { 363 print_error('notpartofdiscussion', 'forum'); 364 } 365 366 $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id()); 367 if (empty($forumentity)) { 368 print_error('invalidforumid', 'forum'); 369 } 370 371 $capabilitymanager = $managerfactory->get_capability_manager($forumentity); 372 $course = $forumentity->get_course_record(); 373 $cm = $forumentity->get_course_module_record(); 374 $modcontext = $forumentity->get_context(); 375 376 require_login($course, false, $cm); 377 378 $replycount = $postvault->get_reply_count_for_post_id_in_discussion_id( 379 $USER, $postentity->get_id(), $discussionentity->get_id(), true); 380 381 if (!empty($confirm) && confirm_sesskey()) { 382 // Do further checks and delete the post. 383 $hasreplies = $replycount > 0; 384 385 try { 386 $capabilitymanager->validate_delete_post($USER, $discussionentity, $postentity, $hasreplies); 387 388 if (!$postentity->has_parent()) { 389 forum_delete_discussion( 390 $discussiondatamapper->to_legacy_object($discussionentity), 391 false, 392 $forumentity->get_course_record(), 393 $forumentity->get_course_module_record(), 394 $forumdatamapper->to_legacy_object($forumentity) 395 ); 396 397 redirect( 398 $urlfactory->get_forum_view_url_from_forum($forumentity), 399 get_string('eventdiscussiondeleted', 'forum'), 400 null, 401 \core\output\notification::NOTIFY_SUCCESS 402 ); 403 } else { 404 forum_delete_post( 405 $postdatamapper->to_legacy_object($postentity), 406 has_capability('mod/forum:deleteanypost', $modcontext), 407 $forumentity->get_course_record(), 408 $forumentity->get_course_module_record(), 409 $forumdatamapper->to_legacy_object($forumentity) 410 ); 411 412 if ($forumentity->get_type() == 'single') { 413 // Single discussion forums are an exception. 414 // We show the forum itself since it only has one discussion thread. 415 $discussionurl = $urlfactory->get_forum_view_url_from_forum($forumentity); 416 } else { 417 $discussionurl = $urlfactory->get_discussion_view_url_from_discussion($discussionentity); 418 } 419 420 redirect( 421 forum_go_back_to($discussionurl), 422 get_string('eventpostdeleted', 'forum'), 423 null, 424 \core\output\notification::NOTIFY_SUCCESS 425 ); 426 } 427 } catch (Exception $e) { 428 redirect( 429 $urlfactory->get_discussion_view_url_from_discussion($discussionentity), 430 $e->getMessage(), 431 null, 432 \core\output\notification::NOTIFY_ERROR 433 ); 434 } 435 436 } else { 437 438 if (!$capabilitymanager->can_delete_post($USER, $discussionentity, $postentity)) { 439 redirect( 440 $urlfactory->get_discussion_view_url_from_discussion($discussionentity), 441 get_string('cannotdeletepost', 'forum'), 442 null, 443 \core\output\notification::NOTIFY_ERROR 444 ); 445 } 446 447 $post = $postdatamapper->to_legacy_object($postentity); 448 $forum = $forumdatamapper->to_legacy_object($forumentity); 449 450 // User just asked to delete something. 451 forum_set_return(); 452 $PAGE->navbar->add(get_string('delete', 'forum')); 453 $PAGE->set_title($course->shortname); 454 $PAGE->set_heading($course->fullname); 455 456 if ($replycount) { 457 if (!has_capability('mod/forum:deleteanypost', $modcontext)) { 458 redirect( 459 forum_go_back_to($urlfactory->get_view_post_url_from_post($postentity)), 460 get_string('couldnotdeletereplies', 'forum'), 461 null, 462 \core\output\notification::NOTIFY_ERROR 463 ); 464 } 465 466 echo $OUTPUT->header(); 467 echo $OUTPUT->heading(format_string($forum->name), 2); 468 echo $OUTPUT->confirm(get_string("deletesureplural", "forum", $replycount + 1), 469 "post.php?delete=$delete&confirm=$delete", 470 $CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'#p'.$post->id); 471 472 $postentities = [$postentity]; 473 if (empty($post->edit)) { 474 $postvault = $vaultfactory->get_post_vault(); 475 $replies = $postvault->get_replies_to_post( 476 $USER, 477 $postentity, 478 // Note: All replies are fetched here as the user has deleteanypost. 479 true, 480 'created ASC' 481 ); 482 $postentities = array_merge($postentities, $replies); 483 } 484 485 $rendererfactory = mod_forum\local\container::get_renderer_factory(); 486 $postsrenderer = $rendererfactory->get_single_discussion_posts_renderer(FORUM_MODE_NESTED, true); 487 echo $postsrenderer->render($USER, [$forumentity], [$discussionentity], $postentities); 488 } else { 489 echo $OUTPUT->header(); 490 echo $OUTPUT->heading(format_string($forum->name), 2); 491 echo $OUTPUT->confirm(get_string("deletesure", "forum", $replycount), 492 "post.php?delete=$delete&confirm=$delete", 493 $CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'#p'.$post->id); 494 495 $rendererfactory = mod_forum\local\container::get_renderer_factory(); 496 $postsrenderer = $rendererfactory->get_single_discussion_posts_renderer(null, true); 497 echo $postsrenderer->render($USER, [$forumentity], [$discussionentity], [$postentity]); 498 } 499 500 } 501 echo $OUTPUT->footer(); 502 die; 503 504} else if (!empty($prune)) { 505 // Pruning. 506 507 $postentity = $postvault->get_from_id($prune); 508 if (empty($postentity)) { 509 print_error('invalidpostid', 'forum'); 510 } 511 512 $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id()); 513 if (empty($discussionentity)) { 514 print_error('notpartofdiscussion', 'forum'); 515 } 516 517 $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id()); 518 if (empty($forumentity)) { 519 print_error('invalidforumid', 'forum'); 520 } 521 522 $capabilitymanager = $managerfactory->get_capability_manager($forumentity); 523 $post = $postdatamapper->to_legacy_object($postentity); 524 $discussion = $discussiondatamapper->to_legacy_object($discussionentity); 525 $forum = $forumdatamapper->to_legacy_object($forumentity); 526 $course = $forumentity->get_course_record(); 527 $modcontext = $forumentity->get_context(); 528 $coursecontext = context_course::instance($course->id); 529 530 if (!$cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) { 531 print_error('invalidcoursemodule'); 532 } 533 534 if (!$postentity->has_parent()) { 535 redirect( 536 $urlfactory->get_discussion_view_url_from_discussion($discussionentity), 537 get_string('alreadyfirstpost', 'forum'), 538 null, 539 \core\output\notification::NOTIFY_ERROR 540 ); 541 } 542 if (!$capabilitymanager->can_split_post($USER, $discussionentity, $postentity)) { 543 redirect( 544 $urlfactory->get_discussion_view_url_from_discussion($discussionentity), 545 get_string('cannotsplit', 'forum'), 546 null, 547 \core\output\notification::NOTIFY_ERROR 548 ); 549 } 550 551 $PAGE->set_cm($cm); 552 $PAGE->set_context($modcontext); 553 554 $prunemform = new mod_forum_prune_form(null, array('prune' => $prune, 'confirm' => $prune)); 555 556 if ($prunemform->is_cancelled()) { 557 redirect(forum_go_back_to($urlfactory->get_discussion_view_url_from_discussion($discussionentity))); 558 } else if ($fromform = $prunemform->get_data()) { 559 // User submits the data. 560 $newdiscussion = new stdClass(); 561 $newdiscussion->course = $discussion->course; 562 $newdiscussion->forum = $discussion->forum; 563 $newdiscussion->name = $name; 564 $newdiscussion->firstpost = $post->id; 565 $newdiscussion->userid = $post->userid; 566 $newdiscussion->groupid = $discussion->groupid; 567 $newdiscussion->assessed = $discussion->assessed; 568 $newdiscussion->usermodified = $post->userid; 569 $newdiscussion->timestart = $discussion->timestart; 570 $newdiscussion->timeend = $discussion->timeend; 571 572 $newid = $DB->insert_record('forum_discussions', $newdiscussion); 573 574 $newpost = new stdClass(); 575 $newpost->id = $post->id; 576 $newpost->parent = 0; 577 $newpost->subject = $name; 578 579 $DB->update_record("forum_posts", $newpost); 580 $postentity = $postvault->get_from_id($postentity->get_id()); 581 582 forum_change_discussionid($post->id, $newid); 583 584 // Update last post in each discussion. 585 forum_discussion_update_last_post($discussion->id); 586 forum_discussion_update_last_post($newid); 587 588 // Fire events to reflect the split.. 589 $params = array( 590 'context' => $modcontext, 591 'objectid' => $discussion->id, 592 'other' => array( 593 'forumid' => $forum->id, 594 ) 595 ); 596 $event = \mod_forum\event\discussion_updated::create($params); 597 $event->trigger(); 598 599 $params = array( 600 'context' => $modcontext, 601 'objectid' => $newid, 602 'other' => array( 603 'forumid' => $forum->id, 604 ) 605 ); 606 $event = \mod_forum\event\discussion_created::create($params); 607 $event->trigger(); 608 609 $params = array( 610 'context' => $modcontext, 611 'objectid' => $post->id, 612 'other' => array( 613 'discussionid' => $newid, 614 'forumid' => $forum->id, 615 'forumtype' => $forum->type, 616 ) 617 ); 618 $event = \mod_forum\event\post_updated::create($params); 619 $event->add_record_snapshot('forum_discussions', $discussion); 620 $event->trigger(); 621 622 redirect( 623 forum_go_back_to($urlfactory->get_discussion_view_url_from_post($postentity)), 624 get_string('discussionsplit', 'forum'), 625 null, 626 \core\output\notification::NOTIFY_SUCCESS 627 ); 628 } else { 629 // Display the prune form. 630 $course = $DB->get_record('course', array('id' => $forum->course)); 631 $subjectstr = format_string($post->subject, true); 632 $PAGE->navbar->add($subjectstr, new moodle_url('/mod/forum/discuss.php', array('d' => $discussion->id))); 633 $PAGE->navbar->add(get_string("prune", "forum")); 634 $PAGE->set_title(format_string($discussion->name).": ".format_string($post->subject)); 635 $PAGE->set_heading($course->fullname); 636 echo $OUTPUT->header(); 637 echo $OUTPUT->heading(format_string($forum->name), 2); 638 echo $OUTPUT->heading(get_string('pruneheading', 'forum'), 3); 639 640 $prunemform->display(); 641 642 $postentity = $entityfactory->get_post_from_stdclass($post); 643 $discussionentity = $entityfactory->get_discussion_from_stdclass($discussion); 644 $forumentity = $entityfactory->get_forum_from_stdclass($forum, $modcontext, $cm, $course); 645 $rendererfactory = mod_forum\local\container::get_renderer_factory(); 646 $postsrenderer = $rendererfactory->get_single_discussion_posts_renderer(null, true); 647 echo $postsrenderer->render($USER, [$forumentity], [$discussionentity], [$postentity]); 648 } 649 650 echo $OUTPUT->footer(); 651 die; 652} else { 653 print_error('unknowaction'); 654 655} 656 657// From now on user must be logged on properly. 658 659require_login($course, false, $cm); 660 661if (isguestuser()) { 662 // Just in case. 663 print_error('noguest'); 664} 665 666$thresholdwarning = forum_check_throttling($forum, $cm); 667$mformpost = new mod_forum_post_form('post.php', [ 668 'course' => $course, 669 'cm' => $cm, 670 'coursecontext' => $coursecontext, 671 'modcontext' => $modcontext, 672 'forum' => $forum, 673 'post' => $post, 674 'subscribe' => \mod_forum\subscriptions::is_subscribed($USER->id, $forum, null, $cm), 675 'thresholdwarning' => $thresholdwarning, 676 'edit' => $edit, 677 'canreplyprivately' => $canreplyprivately, 678 ], 'post', '', array('id' => 'mformforum')); 679 680$draftitemid = file_get_submitted_draft_itemid('attachments'); 681$postid = empty($post->id) ? null : $post->id; 682$attachoptions = mod_forum_post_form::attachment_options($forum); 683file_prepare_draft_area($draftitemid, $modcontext->id, 'mod_forum', 'attachment', $postid, $attachoptions); 684 685// Load data into form NOW! 686 687if ($USER->id != $post->userid) { // Not the original author, so add a message to the end. 688 $data = new stdClass(); 689 $data->date = userdate($post->created); 690 if ($post->messageformat == FORMAT_HTML) { 691 $data->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$USER->id.'&course='.$post->course.'">'. 692 fullname($USER).'</a>'; 693 $post->message .= '<p><span class="edited">('.get_string('editedby', 'forum', $data).')</span></p>'; 694 } else { 695 $data->name = fullname($USER); 696 $post->message .= "\n\n(".get_string('editedby', 'forum', $data).')'; 697 } 698 unset($data); 699} 700 701$formheading = ''; 702if (!empty($parent)) { 703 $heading = get_string("yourreply", "forum"); 704 $formheading = get_string('reply', 'forum'); 705} else { 706 if ($forum->type == 'qanda') { 707 $heading = get_string('yournewquestion', 'forum'); 708 } else { 709 $heading = get_string('yournewtopic', 'forum'); 710 } 711} 712 713$postid = empty($post->id) ? null : $post->id; 714$draftideditor = file_get_submitted_draft_itemid('message'); 715$editoropts = mod_forum_post_form::editor_options($modcontext, $postid); 716$currenttext = file_prepare_draft_area($draftideditor, $modcontext->id, 'mod_forum', 'post', $postid, $editoropts, $post->message); 717$discussionid = isset($discussion) ? $discussion->id : null; 718$discussionsubscribe = \mod_forum\subscriptions::get_user_default_subscription($forum, $coursecontext, $cm, $discussionid); 719 720$mformpost->set_data( 721 array( 722 'attachments' => $draftitemid, 723 'general' => $heading, 724 'subject' => $post->subject, 725 'message' => array( 726 'text' => $currenttext, 727 'format' => !isset($post->messageformat) || !is_numeric($post->messageformat) ? 728 editors_get_preferred_format() : $post->messageformat, 729 'itemid' => $draftideditor 730 ), 731 'discussionsubscribe' => $discussionsubscribe, 732 'mailnow' => !empty($post->mailnow), 733 'userid' => $post->userid, 734 'parent' => $post->parent, 735 'discussion' => $post->discussion, 736 'course' => $course->id, 737 'isprivatereply' => $post->isprivatereply ?? false 738 ) + 739 740 $pageparams + 741 742 (isset($post->format) ? array('format' => $post->format) : array()) + 743 744 (isset($discussion->timestart) ? array('timestart' => $discussion->timestart) : array()) + 745 746 (isset($discussion->timeend) ? array('timeend' => $discussion->timeend) : array()) + 747 748 (isset($discussion->pinned) ? array('pinned' => $discussion->pinned) : array()) + 749 750 (isset($post->groupid) ? array('groupid' => $post->groupid) : array()) + 751 752 (isset($discussion->id) ? array('discussion' => $discussion->id) : array()) 753); 754 755// If we are being redirected via a no_submit_button press OR if the message is being prefilled. 756// then set the initial 'dirty' state. 757// - A prefilled post will exist when being redirected from the inpage reply form. 758// - A no_submit_button press occurs when being redirected from the inpage add new discussion post form. 759$dirty = $prefilledpost ? true : false; 760if ($mformpost->no_submit_button_pressed()) { 761 $data = $mformpost->get_submitted_data(); 762 763 // If a no submit button has been pressed but the default values haven't been then reset the form change. 764 if (!$dirty && isset($data->message['text']) && !empty(trim($data->message['text']))) { 765 $dirty = true; 766 } 767 768 if (!$dirty && isset($data->message['message']) && !empty(trim($data->message['message']))) { 769 $dirty = true; 770 } 771} 772$mformpost->set_initial_dirty_state($dirty); 773 774if ($mformpost->is_cancelled()) { 775 if (!isset($discussion->id) || $forum->type === 'single') { 776 // Single forums don't have a discussion page. 777 redirect($urlfactory->get_forum_view_url_from_forum($forumentity)); 778 } else { 779 redirect($urlfactory->get_discussion_view_url_from_discussion($discussionentity)); 780 } 781} else if ($mformpost->is_submitted() && !$mformpost->no_submit_button_pressed() && $fromform = $mformpost->get_data()) { 782 783 if (empty($SESSION->fromurl)) { 784 $errordestination = $urlfactory->get_forum_view_url_from_forum($forumentity); 785 } else { 786 $errordestination = $SESSION->fromurl; 787 } 788 789 $fromform->itemid = $fromform->message['itemid']; 790 $fromform->messageformat = $fromform->message['format']; 791 $fromform->message = $fromform->message['text']; 792 // WARNING: the $fromform->message array has been overwritten, do not use it anymore! 793 $fromform->messagetrust = trusttext_trusted($modcontext); 794 795 // Clean message text. 796 $fromform = trusttext_pre_edit($fromform, 'message', $modcontext); 797 798 if ($fromform->edit) { 799 // Updating a post. 800 unset($fromform->groupid); 801 $fromform->id = $fromform->edit; 802 $message = ''; 803 804 if (!$capabilitymanager->can_edit_post($USER, $discussionentity, $postentity)) { 805 redirect( 806 $urlfactory->get_view_post_url_from_post($postentity), 807 get_string('cannotupdatepost', 'forum'), 808 null, 809 \core\output\notification::ERROR 810 ); 811 } 812 813 if (isset($fromform->groupinfo) && $capabilitymanager->can_move_discussions($USER)) { 814 // If the user has access to all groups and they are changing the group, then update the post. 815 if (empty($fromform->groupinfo)) { 816 $fromform->groupinfo = -1; 817 } 818 819 if (!$capabilitymanager->can_create_discussions($USER, $fromform->groupinfo)) { 820 redirect( 821 $urlfactory->get_view_post_url_from_post($postentity), 822 get_string('cannotupdatepost', 'forum'), 823 null, 824 \core\output\notification::ERROR 825 ); 826 } 827 828 if ($discussionentity->get_group_id() != $fromform->groupinfo) { 829 $DB->set_field('forum_discussions', 'groupid', $fromform->groupinfo, array('firstpost' => $fromform->id)); 830 } 831 } 832 833 // When editing first post/discussion. 834 if (!$postentity->has_parent()) { 835 if ($capabilitymanager->can_pin_discussions($USER)) { 836 // Can change pinned if we have capability. 837 $fromform->pinned = !empty($fromform->pinned) ? FORUM_DISCUSSION_PINNED : FORUM_DISCUSSION_UNPINNED; 838 } else { 839 // We don't have the capability to change so keep to previous value. 840 unset($fromform->pinned); 841 } 842 } 843 $updatepost = $fromform; 844 $updatepost->forum = $forum->id; 845 if (!forum_update_post($updatepost, $mformpost)) { 846 print_error("couldnotupdate", "forum", $errordestination); 847 } 848 849 forum_trigger_post_updated_event($post, $discussion, $modcontext, $forum); 850 851 if ($USER->id === $postentity->get_author_id()) { 852 $message .= get_string("postupdated", "forum"); 853 } else { 854 $realuser = \core_user::get_user($postentity->get_author_id()); 855 $message .= get_string("editedpostupdated", "forum", fullname($realuser)); 856 } 857 858 $subscribemessage = forum_post_subscription($fromform, $forum, $discussion); 859 if ('single' == $forumentity->get_type()) { 860 // Single discussion forums are an exception. 861 // We show the forum itself since it only has one discussion thread. 862 $discussionurl = $urlfactory->get_forum_view_url_from_forum($forumentity); 863 } else { 864 $discussionurl = $urlfactory->get_view_post_url_from_post($postentity); 865 } 866 867 redirect( 868 forum_go_back_to($discussionurl), 869 $message . $subscribemessage, 870 null, 871 \core\output\notification::NOTIFY_SUCCESS 872 ); 873 874 } else if ($fromform->discussion) { 875 // Adding a new post to an existing discussion 876 // Before we add this we must check that the user will not exceed the blocking threshold. 877 forum_check_blocking_threshold($thresholdwarning); 878 879 unset($fromform->groupid); 880 $message = ''; 881 $addpost = $fromform; 882 $addpost->forum = $forum->id; 883 if ($fromform->id = forum_add_new_post($addpost, $mformpost)) { 884 $postentity = $postvault->get_from_id($fromform->id); 885 $fromform->deleted = 0; 886 $subscribemessage = forum_post_subscription($fromform, $forum, $discussion); 887 888 if (!empty($fromform->mailnow)) { 889 $message .= get_string("postmailnow", "forum"); 890 } else { 891 $message .= '<p>'.get_string("postaddedsuccess", "forum") . '</p>'; 892 $message .= '<p>'.get_string("postaddedtimeleft", "forum", format_time($CFG->maxeditingtime)) . '</p>'; 893 } 894 895 if ($forum->type == 'single') { 896 // Single discussion forums are an exception. 897 // We show the forum itself since it only has one discussion thread. 898 $discussionurl = $urlfactory->get_forum_view_url_from_forum($forumentity); 899 } else { 900 $discussionurl = $urlfactory->get_view_post_url_from_post($postentity); 901 } 902 903 $params = array( 904 'context' => $modcontext, 905 'objectid' => $fromform->id, 906 'other' => array( 907 'discussionid' => $discussion->id, 908 'forumid' => $forum->id, 909 'forumtype' => $forum->type, 910 ) 911 ); 912 $event = \mod_forum\event\post_created::create($params); 913 $event->add_record_snapshot('forum_posts', $fromform); 914 $event->add_record_snapshot('forum_discussions', $discussion); 915 $event->trigger(); 916 917 // Update completion state. 918 $completion = new completion_info($course); 919 if ($completion->is_enabled($cm) && 920 ($forum->completionreplies || $forum->completionposts)) { 921 $completion->update_state($cm, COMPLETION_COMPLETE); 922 } 923 924 redirect( 925 forum_go_back_to($discussionurl), 926 $message . $subscribemessage, 927 null, 928 \core\output\notification::NOTIFY_SUCCESS 929 ); 930 931 } else { 932 print_error("couldnotadd", "forum", $errordestination); 933 } 934 exit; 935 936 } else { 937 // Adding a new discussion. 938 // The location to redirect to after successfully posting. 939 $redirectto = new moodle_url('/mod/forum/view.php', array('f' => $fromform->forum)); 940 941 $fromform->mailnow = empty($fromform->mailnow) ? 0 : 1; 942 943 $discussion = $fromform; 944 $discussion->name = $fromform->subject; 945 $discussion->timelocked = 0; 946 947 $newstopic = false; 948 if ($forum->type == 'news' && !$fromform->parent) { 949 $newstopic = true; 950 } 951 952 if (!empty($fromform->pinned) && $capabilitymanager->can_pin_discussions($USER)) { 953 $discussion->pinned = FORUM_DISCUSSION_PINNED; 954 } else { 955 $discussion->pinned = FORUM_DISCUSSION_UNPINNED; 956 } 957 958 $allowedgroups = array(); 959 $groupstopostto = array(); 960 961 // If we are posting a copy to all groups the user has access to. 962 if (isset($fromform->posttomygroups)) { 963 // Post to each of my groups. 964 require_capability('mod/forum:canposttomygroups', $modcontext); 965 966 // Fetch all of this user's groups. 967 // Note: all groups are returned when in visible groups mode so we must manually filter. 968 $allowedgroups = groups_get_activity_allowed_groups($cm); 969 foreach ($allowedgroups as $groupid => $group) { 970 if ($capabilitymanager->can_create_discussions($USER, $groupid)) { 971 $groupstopostto[] = $groupid; 972 } 973 } 974 } else if (isset($fromform->groupinfo)) { 975 // Use the value provided in the dropdown group selection. 976 $groupstopostto[] = $fromform->groupinfo; 977 $redirectto->param('group', $fromform->groupinfo); 978 } else if (isset($fromform->groupid) && !empty($fromform->groupid)) { 979 // Use the value provided in the hidden form element instead. 980 $groupstopostto[] = $fromform->groupid; 981 $redirectto->param('group', $fromform->groupid); 982 } else { 983 // Use the value for all participants instead. 984 $groupstopostto[] = -1; 985 } 986 987 // Before we post this we must check that the user will not exceed the blocking threshold. 988 forum_check_blocking_threshold($thresholdwarning); 989 990 foreach ($groupstopostto as $group) { 991 if (!$capabilitymanager->can_create_discussions($USER, $groupid)) { 992 print_error('cannotcreatediscussion', 'forum'); 993 } 994 995 $discussion->groupid = $group; 996 $message = ''; 997 if ($discussion->id = forum_add_discussion($discussion, $mformpost)) { 998 999 $params = array( 1000 'context' => $modcontext, 1001 'objectid' => $discussion->id, 1002 'other' => array( 1003 'forumid' => $forum->id, 1004 ) 1005 ); 1006 $event = \mod_forum\event\discussion_created::create($params); 1007 $event->add_record_snapshot('forum_discussions', $discussion); 1008 $event->trigger(); 1009 1010 if ($fromform->mailnow) { 1011 $message .= get_string("postmailnow", "forum"); 1012 } else { 1013 $message .= '<p>'.get_string("postaddedsuccess", "forum") . '</p>'; 1014 $message .= '<p>'.get_string("postaddedtimeleft", "forum", format_time($CFG->maxeditingtime)) . '</p>'; 1015 } 1016 1017 $subscribemessage = forum_post_subscription($fromform, $forum, $discussion); 1018 } else { 1019 print_error("couldnotadd", "forum", $errordestination); 1020 } 1021 } 1022 1023 // Update completion status. 1024 $completion = new completion_info($course); 1025 if ($completion->is_enabled($cm) && 1026 ($forum->completiondiscussions || $forum->completionposts)) { 1027 $completion->update_state($cm, COMPLETION_COMPLETE); 1028 } 1029 1030 // Redirect back to the discussion. 1031 redirect( 1032 forum_go_back_to($redirectto->out()), 1033 $message . $subscribemessage, 1034 null, 1035 \core\output\notification::NOTIFY_SUCCESS 1036 ); 1037 } 1038} 1039 1040 1041// This section is only shown after all checks are in place, and the forumentity and any relevant discussion and post 1042// entity are available. 1043 1044if (!empty($discussionentity)) { 1045 $titlesubject = format_string($discussionentity->get_name(), true); 1046} else if ('news' == $forumentity->get_type()) { 1047 $titlesubject = get_string("addanewtopic", "forum"); 1048} else { 1049 $titlesubject = get_string("addanewdiscussion", "forum"); 1050} 1051 1052if (empty($post->edit)) { 1053 $post->edit = ''; 1054} 1055 1056if (empty($discussion->name)) { 1057 if (empty($discussion)) { 1058 $discussion = new stdClass(); 1059 } 1060 $discussion->name = $forum->name; 1061} 1062 1063$strdiscussionname = ''; 1064if ('single' == $forumentity->get_type()) { 1065 // There is only one discussion thread for this forum type. We should 1066 // not show the discussion name (same as forum name in this case) in 1067 // the breadcrumbs. 1068 $strdiscussionname = ''; 1069} else if (!empty($discussionentity)) { 1070 // Show the discussion name in the breadcrumbs. 1071 $strdiscussionname = format_string($discussionentity->get_name()) . ': '; 1072} 1073 1074$forcefocus = empty($reply) ? null : 'message'; 1075 1076if (!empty($discussion->id)) { 1077 $PAGE->navbar->add($titlesubject, $urlfactory->get_discussion_view_url_from_discussion($discussionentity)); 1078} 1079 1080if ($post->parent) { 1081 $PAGE->navbar->add(get_string('reply', 'forum')); 1082} 1083 1084if ($edit) { 1085 $PAGE->navbar->add(get_string('edit', 'forum')); 1086} 1087 1088$PAGE->set_title("{$course->shortname}: {$strdiscussionname}{$titlesubject}"); 1089$PAGE->set_heading($course->fullname); 1090 1091echo $OUTPUT->header(); 1092echo $OUTPUT->heading(format_string($forum->name), 2); 1093 1094// Checkup. 1095if (!empty($parententity) && !$capabilitymanager->can_view_post($USER, $discussionentity, $parententity)) { 1096 print_error('cannotreply', 'forum'); 1097} 1098 1099if (empty($parententity) && empty($edit) && !$capabilitymanager->can_create_discussions($USER, $groupid)) { 1100 print_error('cannotcreatediscussion', 'forum'); 1101} 1102 1103if (!empty($discussionentity) && 'qanda' == $forumentity->get_type()) { 1104 $displaywarning = $capabilitymanager->must_post_before_viewing_discussion($USER, $discussionentity); 1105 $displaywarning = $displaywarning && !forum_user_has_posted($forumentity->get_id(), $discussionentity->get_id(), $USER->id); 1106 if ($displaywarning) { 1107 echo $OUTPUT->notification(get_string('qandanotify', 'forum')); 1108 } 1109} 1110 1111// If there is a warning message and we are not editing a post we need to handle the warning. 1112if (!empty($thresholdwarning) && !$edit) { 1113 // Here we want to throw an exception if they are no longer allowed to post. 1114 forum_check_blocking_threshold($thresholdwarning); 1115} 1116 1117if (!empty($parententity)) { 1118 $postentities = [$parententity]; 1119 1120 if (empty($post->edit)) { 1121 if ('qanda' != $forumentity->get_type() || forum_user_can_see_discussion($forum, $discussion, $modcontext)) { 1122 $replies = $postvault->get_replies_to_post( 1123 $USER, 1124 $parententity, 1125 $capabilitymanager->can_view_any_private_reply($USER), 1126 'created ASC' 1127 ); 1128 $postentities = array_merge($postentities, $replies); 1129 } 1130 } 1131 1132 $rendererfactory = mod_forum\local\container::get_renderer_factory(); 1133 $postsrenderer = $rendererfactory->get_single_discussion_posts_renderer(FORUM_MODE_THREADED, true); 1134 echo $postsrenderer->render($USER, [$forumentity], [$discussionentity], $postentities); 1135} else { 1136 if (!empty($forum->intro)) { 1137 echo $OUTPUT->box(format_module_intro('forum', $forum, $cm->id), 'generalbox', 'intro'); 1138 } 1139} 1140 1141// Call print disclosure for enabled plagiarism plugins. 1142if (!empty($CFG->enableplagiarism)) { 1143 require_once($CFG->libdir.'/plagiarismlib.php'); 1144 echo plagiarism_print_disclosure($cm->id); 1145} 1146 1147if (!empty($formheading)) { 1148 echo $OUTPUT->heading($formheading, 2, array('class' => 'accesshide')); 1149} 1150 1151if (!empty($postentity)) { 1152 $data = (object) [ 1153 'tags' => core_tag_tag::get_item_tags_array('mod_forum', 'forum_posts', $postentity->get_id()) 1154 ]; 1155 $mformpost->set_data($data); 1156} 1157 1158$mformpost->display(); 1159 1160echo $OUTPUT->footer(); 1161