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