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