Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
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 throw new \moodle_exception('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 throw new \moodle_exception('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 throw new \moodle_exception("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'), get_login_url(), $referer, [ 109 'confirmtitle' => get_string('noguestpost:title', 'forum'), 110 'continuestr' => get_string('login') 111 ]); 112 echo $OUTPUT->footer(); 113 exit; 114 } 115 116 require_login(0, false); // Script is useless unless they're logged in. 117 118 $canreplyprivately = false; 119 120 if (!empty($forum)) { 121 // User is starting a new discussion in a forum. 122 $forumentity = $forumvault->get_from_id($forum); 123 if (empty($forumentity)) { 124 throw new \moodle_exception('invalidforumid', 'forum'); 125 } 126 127 $capabilitymanager = $managerfactory->get_capability_manager($forumentity); 128 $forum = $forumdatamapper->to_legacy_object($forumentity); 129 $course = $forumentity->get_course_record(); 130 if (!$cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) { 131 throw new \moodle_exception("invalidcoursemodule"); 132 } 133 134 // Retrieve the contexts. 135 $modcontext = $forumentity->get_context(); 136 $coursecontext = context_course::instance($course->id); 137 138 if ($forumentity->is_in_group_mode() && null === $groupid) { 139 $groupid = groups_get_activity_group($cm); 140 } 141 142 if (!$capabilitymanager->can_create_discussions($USER, $groupid)) { 143 if (!isguestuser()) { 144 if (!is_enrolled($coursecontext)) { 145 if (enrol_selfenrol_available($course->id)) { 146 $SESSION->wantsurl = qualified_me(); 147 $SESSION->enrolcancel = get_local_referer(false); 148 redirect(new moodle_url('/enrol/index.php', array('id' => $course->id, 149 'returnurl' => '/mod/forum/view.php?f=' . $forum->id)), 150 get_string('youneedtoenrol')); 151 } 152 } 153 } 154 throw new \moodle_exception('nopostforum', 'forum'); 155 } 156 157 if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $modcontext)) { 158 redirect( 159 $urlfactory->get_course_url_from_forum($forumentity), 160 get_string('activityiscurrentlyhidden'), 161 null, 162 \core\output\notification::NOTIFY_ERROR 163 ); 164 } 165 166 // Load up the $post variable. 167 168 $post = new stdClass(); 169 $post->course = $course->id; 170 $post->forum = $forum->id; 171 $post->discussion = 0; // Ie discussion # not defined yet. 172 $post->parent = 0; 173 $post->subject = $subject; 174 $post->userid = $USER->id; 175 $post->message = $prefilledpost; 176 $post->messageformat = editors_get_preferred_format(); 177 $post->messagetrust = 0; 178 $post->groupid = $groupid; 179 180 // Unsetting this will allow the correct return URL to be calculated later. 181 unset($SESSION->fromdiscussion); 182 183 } else if (!empty($reply)) { 184 // User is writing a new reply. 185 186 $parententity = $postvault->get_from_id($reply); 187 if (empty($parententity)) { 188 throw new \moodle_exception('invalidparentpostid', 'forum'); 189 } 190 191 $discussionentity = $discussionvault->get_from_id($parententity->get_discussion_id()); 192 if (empty($discussionentity)) { 193 throw new \moodle_exception('notpartofdiscussion', 'forum'); 194 } 195 196 $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id()); 197 if (empty($forumentity)) { 198 throw new \moodle_exception('invalidforumid', 'forum'); 199 } 200 201 $capabilitymanager = $managerfactory->get_capability_manager($forumentity); 202 $parent = $postdatamapper->to_legacy_object($parententity); 203 $discussion = $discussiondatamapper->to_legacy_object($discussionentity); 204 $forum = $forumdatamapper->to_legacy_object($forumentity); 205 $course = $forumentity->get_course_record(); 206 $modcontext = $forumentity->get_context(); 207 $coursecontext = context_course::instance($course->id); 208 209 if (!$cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) { 210 throw new \moodle_exception('invalidcoursemodule'); 211 } 212 213 // Ensure lang, theme, etc. is set up properly. MDL-6926. 214 $PAGE->set_cm($cm, $course, $forum); 215 216 if (!$capabilitymanager->can_reply_to_post($USER, $discussionentity, $parententity)) { 217 if (!isguestuser()) { 218 if (!is_enrolled($coursecontext)) { // User is a guest here! 219 $SESSION->wantsurl = qualified_me(); 220 $SESSION->enrolcancel = get_local_referer(false); 221 redirect(new moodle_url('/enrol/index.php', array('id' => $course->id, 222 'returnurl' => '/mod/forum/view.php?f=' . $forum->id)), 223 get_string('youneedtoenrol')); 224 } 225 226 // The forum has been locked. Just redirect back to the discussion page. 227 if (forum_discussion_is_locked($forum, $discussion)) { 228 redirect(new moodle_url('/mod/forum/discuss.php', array('d' => $discussion->id))); 229 } 230 } 231 throw new \moodle_exception('nopostforum', 'forum'); 232 } 233 234 // Make sure user can post here. 235 if (isset($cm->groupmode) && empty($course->groupmodeforce)) { 236 $groupmode = $cm->groupmode; 237 } else { 238 $groupmode = $course->groupmode; 239 } 240 if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $modcontext)) { 241 if ($discussion->groupid == -1) { 242 throw new \moodle_exception('nopostforum', 'forum'); 243 } else { 244 if (!groups_is_member($discussion->groupid)) { 245 throw new \moodle_exception('nopostforum', 'forum'); 246 } 247 } 248 } 249 250 if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $modcontext)) { 251 throw new \moodle_exception("activityiscurrentlyhidden"); 252 } 253 254 if ($parententity->is_private_reply()) { 255 throw new \moodle_exception('cannotreplytoprivatereply', 'forum'); 256 } 257 258 // We always are going to honor the preferred format. We are creating a new post. 259 $preferredformat = editors_get_preferred_format(); 260 261 // Only if there are prefilled contents coming. 262 if (!empty($prefilledpost)) { 263 // If the prefilled post is not HTML and the preferred format is HTML, convert to it. 264 if ($prefilledpostformat != FORMAT_HTML and $preferredformat == FORMAT_HTML) { 265 $prefilledpost = format_text($prefilledpost, $prefilledpostformat, ['context' => $modcontext]); 266 } 267 } 268 269 // Load up the $post variable. 270 $post = new stdClass(); 271 $post->course = $course->id; 272 $post->forum = $forum->id; 273 $post->discussion = $parent->discussion; 274 $post->parent = $parent->id; 275 $post->subject = $subject ? $subject : $parent->subject; 276 $post->userid = $USER->id; 277 $post->parentpostauthor = $parent->userid; 278 $post->message = $prefilledpost; 279 $post->messageformat = $preferredformat; 280 $post->isprivatereply = $prefilledprivatereply; 281 $canreplyprivately = $capabilitymanager->can_reply_privately_to_post($USER, $parententity); 282 283 $post->groupid = ($discussion->groupid == -1) ? 0 : $discussion->groupid; 284 285 $strre = get_string('re', 'forum'); 286 if (!(substr($post->subject, 0, strlen($strre)) == $strre)) { 287 $post->subject = $strre.' '.$post->subject; 288 } 289 290 // Unsetting this will allow the correct return URL to be calculated later. 291 unset($SESSION->fromdiscussion); 292 293 } else if (!empty($edit)) { 294 // User is editing their own post. 295 296 $postentity = $postvault->get_from_id($edit); 297 if (empty($postentity)) { 298 throw new \moodle_exception('invalidpostid', 'forum'); 299 } 300 if ($postentity->has_parent()) { 301 $parententity = $postvault->get_from_id($postentity->get_parent_id()); 302 $parent = $postdatamapper->to_legacy_object($parententity); 303 } 304 305 $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id()); 306 if (empty($discussionentity)) { 307 throw new \moodle_exception('notpartofdiscussion', 'forum'); 308 } 309 310 $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id()); 311 if (empty($forumentity)) { 312 throw new \moodle_exception('invalidforumid', 'forum'); 313 } 314 315 $capabilitymanager = $managerfactory->get_capability_manager($forumentity); 316 $post = $postdatamapper->to_legacy_object($postentity); 317 $discussion = $discussiondatamapper->to_legacy_object($discussionentity); 318 $forum = $forumdatamapper->to_legacy_object($forumentity); 319 $course = $forumentity->get_course_record(); 320 $modcontext = $forumentity->get_context(); 321 $coursecontext = context_course::instance($course->id); 322 323 if (!$cm = get_coursemodule_from_instance("forum", $forum->id, $course->id)) { 324 throw new \moodle_exception('invalidcoursemodule'); 325 } 326 327 $PAGE->set_cm($cm, $course, $forum); 328 329 if (!($forum->type == 'news' && !$post->parent && $discussion->timestart > time())) { 330 if (((time() - $post->created) > $CFG->maxeditingtime) and 331 !has_capability('mod/forum:editanypost', $modcontext)) { 332 throw new \moodle_exception('maxtimehaspassed', 'forum', '', format_time($CFG->maxeditingtime)); 333 } 334 } 335 if (($post->userid <> $USER->id) and 336 !has_capability('mod/forum:editanypost', $modcontext)) { 337 throw new \moodle_exception('cannoteditposts', 'forum'); 338 } 339 340 // Load up the $post variable. 341 $post->edit = $edit; 342 $post->course = $course->id; 343 $post->forum = $forum->id; 344 $post->groupid = ($discussion->groupid == -1) ? 0 : $discussion->groupid; 345 if ($postentity->has_parent()) { 346 $canreplyprivately = forum_user_can_reply_privately($modcontext, $parent); 347 } 348 349 $post = trusttext_pre_edit($post, 'message', $modcontext); 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 throw new \moodle_exception('invalidpostid', 'forum'); 360 } 361 362 $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id()); 363 if (empty($discussionentity)) { 364 throw new \moodle_exception('notpartofdiscussion', 'forum'); 365 } 366 367 $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id()); 368 if (empty($forumentity)) { 369 throw new \moodle_exception('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 throw new \moodle_exception('invalidpostid', 'forum'); 517 } 518 519 $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id()); 520 if (empty($discussionentity)) { 521 throw new \moodle_exception('notpartofdiscussion', 'forum'); 522 } 523 524 $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id()); 525 if (empty($forumentity)) { 526 throw new \moodle_exception('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 throw new \moodle_exception('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 throw new \moodle_exception('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 throw new \moodle_exception('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 // Do not clean text here, text cleaning can be done only after conversion to HTML. 803 // Word counting now uses text formatting, there is no need to abuse trusttext_pre_edit() here. 804 805 if ($fromform->edit) { 806 // Updating a post. 807 unset($fromform->groupid); 808 $fromform->id = $fromform->edit; 809 $message = ''; 810 811 if (!$capabilitymanager->can_edit_post($USER, $discussionentity, $postentity)) { 812 redirect( 813 $urlfactory->get_view_post_url_from_post($postentity), 814 get_string('cannotupdatepost', 'forum'), 815 null, 816 \core\output\notification::ERROR 817 ); 818 } 819 820 if (isset($fromform->groupinfo) && $capabilitymanager->can_move_discussions($USER)) { 821 // If the user has access to all groups and they are changing the group, then update the post. 822 if (empty($fromform->groupinfo)) { 823 $fromform->groupinfo = -1; 824 } 825 826 if (!$capabilitymanager->can_create_discussions($USER, $fromform->groupinfo)) { 827 redirect( 828 $urlfactory->get_view_post_url_from_post($postentity), 829 get_string('cannotupdatepost', 'forum'), 830 null, 831 \core\output\notification::ERROR 832 ); 833 } 834 835 if ($discussionentity->get_group_id() != $fromform->groupinfo) { 836 $DB->set_field('forum_discussions', 'groupid', $fromform->groupinfo, array('firstpost' => $fromform->id)); 837 } 838 } 839 840 // When editing first post/discussion. 841 if (!$postentity->has_parent()) { 842 if ($capabilitymanager->can_pin_discussions($USER)) { 843 // Can change pinned if we have capability. 844 $fromform->pinned = !empty($fromform->pinned) ? FORUM_DISCUSSION_PINNED : FORUM_DISCUSSION_UNPINNED; 845 } else { 846 // We don't have the capability to change so keep to previous value. 847 unset($fromform->pinned); 848 } 849 } 850 $updatepost = $fromform; 851 $updatepost->forum = $forum->id; 852 if (!forum_update_post($updatepost, $mformpost)) { 853 throw new \moodle_exception("couldnotupdate", "forum", $errordestination); 854 } 855 856 forum_trigger_post_updated_event($post, $discussion, $modcontext, $forum); 857 858 if ($USER->id === $postentity->get_author_id()) { 859 $message .= get_string("postupdated", "forum"); 860 } else { 861 $realuser = \core_user::get_user($postentity->get_author_id()); 862 $message .= get_string("editedpostupdated", "forum", fullname($realuser)); 863 } 864 865 $subscribemessage = forum_post_subscription($fromform, $forum, $discussion); 866 if ('single' == $forumentity->get_type()) { 867 // Single discussion forums are an exception. 868 // We show the forum itself since it only has one discussion thread. 869 $discussionurl = $urlfactory->get_forum_view_url_from_forum($forumentity); 870 } else { 871 $discussionurl = $urlfactory->get_view_post_url_from_post($postentity); 872 } 873 874 redirect( 875 forum_go_back_to($discussionurl), 876 $message . $subscribemessage, 877 null, 878 \core\output\notification::NOTIFY_SUCCESS 879 ); 880 881 } else if ($fromform->discussion) { 882 // Adding a new post to an existing discussion 883 // Before we add this we must check that the user will not exceed the blocking threshold. 884 forum_check_blocking_threshold($thresholdwarning); 885 886 unset($fromform->groupid); 887 $message = ''; 888 $addpost = $fromform; 889 $addpost->forum = $forum->id; 890 if ($fromform->id = forum_add_new_post($addpost, $mformpost)) { 891 $postentity = $postvault->get_from_id($fromform->id); 892 $fromform->deleted = 0; 893 $subscribemessage = forum_post_subscription($fromform, $forum, $discussion); 894 895 if (!empty($fromform->mailnow)) { 896 $message .= get_string("postmailnow", "forum"); 897 } else { 898 $message .= '<p>'.get_string("postaddedsuccess", "forum") . '</p>'; 899 $message .= '<p>'.get_string("postaddedtimeleft", "forum", format_time($CFG->maxeditingtime)) . '</p>'; 900 } 901 902 if ($forum->type == 'single') { 903 // Single discussion forums are an exception. 904 // We show the forum itself since it only has one discussion thread. 905 $discussionurl = $urlfactory->get_forum_view_url_from_forum($forumentity); 906 } else { 907 $discussionurl = $urlfactory->get_view_post_url_from_post($postentity); 908 } 909 910 $params = array( 911 'context' => $modcontext, 912 'objectid' => $fromform->id, 913 'other' => array( 914 'discussionid' => $discussion->id, 915 'forumid' => $forum->id, 916 'forumtype' => $forum->type, 917 ) 918 ); 919 $event = \mod_forum\event\post_created::create($params); 920 $event->add_record_snapshot('forum_posts', $fromform); 921 $event->add_record_snapshot('forum_discussions', $discussion); 922 $event->trigger(); 923 924 // Update completion state. 925 $completion = new completion_info($course); 926 if ($completion->is_enabled($cm) && 927 ($forum->completionreplies || $forum->completionposts)) { 928 $completion->update_state($cm, COMPLETION_COMPLETE); 929 } 930 931 redirect( 932 forum_go_back_to($discussionurl), 933 $message . $subscribemessage, 934 null, 935 \core\output\notification::NOTIFY_SUCCESS 936 ); 937 938 } else { 939 throw new \moodle_exception("couldnotadd", "forum", $errordestination); 940 } 941 exit; 942 943 } else { 944 // Adding a new discussion. 945 // The location to redirect to after successfully posting. 946 $redirectto = new moodle_url('/mod/forum/view.php', array('f' => $fromform->forum)); 947 948 $fromform->mailnow = empty($fromform->mailnow) ? 0 : 1; 949 950 $discussion = $fromform; 951 $discussion->name = $fromform->subject; 952 $discussion->timelocked = 0; 953 954 $newstopic = false; 955 if ($forum->type == 'news' && !$fromform->parent) { 956 $newstopic = true; 957 } 958 959 if (!empty($fromform->pinned) && $capabilitymanager->can_pin_discussions($USER)) { 960 $discussion->pinned = FORUM_DISCUSSION_PINNED; 961 } else { 962 $discussion->pinned = FORUM_DISCUSSION_UNPINNED; 963 } 964 965 $allowedgroups = array(); 966 $groupstopostto = array(); 967 968 // If we are posting a copy to all groups the user has access to. 969 if (isset($fromform->posttomygroups)) { 970 // Post to each of my groups. 971 require_capability('mod/forum:canposttomygroups', $modcontext); 972 973 // Fetch all of this user's groups. 974 // Note: all groups are returned when in visible groups mode so we must manually filter. 975 $allowedgroups = groups_get_activity_allowed_groups($cm); 976 foreach ($allowedgroups as $groupid => $group) { 977 if ($capabilitymanager->can_create_discussions($USER, $groupid)) { 978 $groupstopostto[] = $groupid; 979 } 980 } 981 } else if (isset($fromform->groupinfo)) { 982 // Use the value provided in the dropdown group selection. 983 $groupstopostto[] = $fromform->groupinfo; 984 $redirectto->param('group', $fromform->groupinfo); 985 } else if (isset($fromform->groupid) && !empty($fromform->groupid)) { 986 // Use the value provided in the hidden form element instead. 987 $groupstopostto[] = $fromform->groupid; 988 $redirectto->param('group', $fromform->groupid); 989 } else { 990 // Use the value for all participants instead. 991 $groupstopostto[] = -1; 992 } 993 994 // Before we post this we must check that the user will not exceed the blocking threshold. 995 forum_check_blocking_threshold($thresholdwarning); 996 997 foreach ($groupstopostto as $group) { 998 if (!$capabilitymanager->can_create_discussions($USER, $group)) { 999 throw new \moodle_exception('cannotcreatediscussion', 'forum'); 1000 } 1001 1002 $discussion->groupid = $group; 1003 $message = ''; 1004 if ($discussion->id = forum_add_discussion($discussion, $mformpost)) { 1005 1006 $params = array( 1007 'context' => $modcontext, 1008 'objectid' => $discussion->id, 1009 'other' => array( 1010 'forumid' => $forum->id, 1011 ) 1012 ); 1013 $event = \mod_forum\event\discussion_created::create($params); 1014 $event->add_record_snapshot('forum_discussions', $discussion); 1015 $event->trigger(); 1016 1017 if ($fromform->mailnow) { 1018 $message .= get_string("postmailnow", "forum"); 1019 } else { 1020 $message .= '<p>'.get_string("postaddedsuccess", "forum") . '</p>'; 1021 $message .= '<p>'.get_string("postaddedtimeleft", "forum", format_time($CFG->maxeditingtime)) . '</p>'; 1022 } 1023 1024 $subscribemessage = forum_post_subscription($fromform, $forum, $discussion); 1025 } else { 1026 throw new \moodle_exception("couldnotadd", "forum", $errordestination); 1027 } 1028 } 1029 1030 // Update completion status. 1031 $completion = new completion_info($course); 1032 if ($completion->is_enabled($cm) && 1033 ($forum->completiondiscussions || $forum->completionposts)) { 1034 $completion->update_state($cm, COMPLETION_COMPLETE); 1035 } 1036 1037 // Redirect back to the discussion. 1038 redirect( 1039 forum_go_back_to($redirectto->out()), 1040 $message . $subscribemessage, 1041 null, 1042 \core\output\notification::NOTIFY_SUCCESS 1043 ); 1044 } 1045 } 1046 1047 1048 // This section is only shown after all checks are in place, and the forumentity and any relevant discussion and post 1049 // entity are available. 1050 1051 if (!empty($discussionentity)) { 1052 $titlesubject = format_string($discussionentity->get_name(), true); 1053 } else if ('news' == $forumentity->get_type()) { 1054 $titlesubject = get_string("addanewtopic", "forum"); 1055 } else { 1056 $titlesubject = get_string("addanewdiscussion", "forum"); 1057 } 1058 1059 if (empty($post->edit)) { 1060 $post->edit = ''; 1061 } 1062 1063 if (empty($discussion->name)) { 1064 if (empty($discussion)) { 1065 $discussion = new stdClass(); 1066 } 1067 $discussion->name = $forum->name; 1068 } 1069 1070 $strdiscussionname = ''; 1071 if ('single' == $forumentity->get_type()) { 1072 // There is only one discussion thread for this forum type. We should 1073 // not show the discussion name (same as forum name in this case) in 1074 // the breadcrumbs. 1075 $strdiscussionname = ''; 1076 } else if (!empty($discussionentity)) { 1077 // Show the discussion name in the breadcrumbs. 1078 $strdiscussionname = format_string($discussionentity->get_name()) . ': '; 1079 } 1080 1081 $forcefocus = empty($reply) ? null : 'message'; 1082 1083 if (!empty($discussion->id)) { 1084 $PAGE->navbar->add($titlesubject, $urlfactory->get_discussion_view_url_from_discussion($discussionentity)); 1085 } 1086 1087 if ($edit) { 1088 $PAGE->navbar->add(get_string('editdiscussiontopic', 'forum'), $PAGE->url); 1089 } else if ($reply) { 1090 $PAGE->navbar->add(get_string('addreply', 'forum')); 1091 } else { 1092 $PAGE->navbar->add(get_string('addanewdiscussion', 'forum'), $PAGE->url); 1093 } 1094 1095 $PAGE->set_title("{$course->shortname}: {$strdiscussionname}{$titlesubject}"); 1096 $PAGE->set_heading($course->fullname); 1097 $PAGE->set_secondary_active_tab("modulepage"); 1098 $activityheaderconfig['hidecompletion'] = true; 1099 $activityheaderconfig['description'] = ''; 1100 1101 // Remove the activity description. 1102 $PAGE->activityheader->set_attrs($activityheaderconfig); 1103 echo $OUTPUT->header(); 1104 1105 if ($edit) { 1106 echo $OUTPUT->heading(get_string('editdiscussiontopic', 'forum'), 2); 1107 } else if ($reply) { 1108 echo $OUTPUT->heading(get_string('replypostdiscussion', 'forum'), 2); 1109 } else { 1110 echo $OUTPUT->heading(get_string('addanewdiscussion', 'forum'), 2); 1111 } 1112 1113 // Checkup. 1114 if (!empty($parententity) && !$capabilitymanager->can_view_post($USER, $discussionentity, $parententity)) { 1115 throw new \moodle_exception('cannotreply', 'forum'); 1116 } 1117 1118 if (empty($parententity) && empty($edit) && !$capabilitymanager->can_create_discussions($USER, $groupid)) { 1119 throw new \moodle_exception('cannotcreatediscussion', 'forum'); 1120 } 1121 1122 if (!empty($discussionentity) && 'qanda' == $forumentity->get_type()) { 1123 $displaywarning = $capabilitymanager->must_post_before_viewing_discussion($USER, $discussionentity); 1124 $displaywarning = $displaywarning && !forum_user_has_posted($forumentity->get_id(), $discussionentity->get_id(), $USER->id); 1125 if ($displaywarning) { 1126 echo $OUTPUT->notification(get_string('qandanotify', 'forum')); 1127 } 1128 } 1129 1130 // If there is a warning message and we are not editing a post we need to handle the warning. 1131 if (!empty($thresholdwarning) && !$edit) { 1132 // Here we want to throw an exception if they are no longer allowed to post. 1133 forum_check_blocking_threshold($thresholdwarning); 1134 } 1135 1136 if (!empty($parententity)) { 1137 $postentities = [$parententity]; 1138 1139 if (empty($post->edit)) { 1140 if ('qanda' != $forumentity->get_type() || forum_user_can_see_discussion($forum, $discussion, $modcontext)) { 1141 $replies = $postvault->get_replies_to_post( 1142 $USER, 1143 $parententity, 1144 $capabilitymanager->can_view_any_private_reply($USER), 1145 'created ASC' 1146 ); 1147 $postentities = array_merge($postentities, $replies); 1148 } 1149 } 1150 1151 $rendererfactory = mod_forum\local\container::get_renderer_factory(); 1152 $postsrenderer = $rendererfactory->get_single_discussion_posts_renderer(FORUM_MODE_THREADED, true); 1153 echo $postsrenderer->render($USER, [$forumentity], [$discussionentity], $postentities); 1154 } 1155 1156 // Call print disclosure for enabled plagiarism plugins. 1157 if (!empty($CFG->enableplagiarism)) { 1158 require_once($CFG->libdir.'/plagiarismlib.php'); 1159 echo plagiarism_print_disclosure($cm->id); 1160 } 1161 1162 if (!empty($formheading)) { 1163 echo $OUTPUT->heading($formheading, 2, array('class' => 'accesshide')); 1164 } 1165 1166 if (!empty($postentity)) { 1167 $data = (object) [ 1168 'tags' => core_tag_tag::get_item_tags_array('mod_forum', 'forum_posts', $postentity->get_id()) 1169 ]; 1170 $mformpost->set_data($data); 1171 } 1172 1173 $mformpost->display(); 1174 1175 echo $OUTPUT->footer();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body