/** * Adds a discussion to the list (internal use only). * @param forum_discussion $discussion */ function add_discussion($discussion) { if ($discussion->is_sticky() && !$discussion->is_deleted()) { $this->stickydiscussions[$discussion->get_id()] = $discussion; } else { $this->normaldiscussions[$discussion->get_id()] = $discussion; } }
/** * Convenience function for subclasses. Returns HTML code suitable to * use for a button in this area. * @param forum_discussion $discussion * @param string $name Text of button * @param string $script Name/path of .php script (relative to mod/forumng) * @param bool $post If true, makes the button send a POST request * @param array $options If included, passes these options as well as 'd' * @param string $extrahtml If specified, adds this HTML at end of (just * inside) the form * @param bool $highlight If true, adds a highlight class to the form * @return string HTML code for button */ protected static function get_button($discussion, $name, $script, $post = false, $options = array(), $extrahtml = '', $highlight = false) { $method = $post ? 'post' : 'get'; $optionshtml = ''; $options['d'] = $discussion->get_id(); if ($discussion->get_forum()->is_shared()) { $options['clone'] = $discussion->get_forum()->get_course_module_id(); } if ($post) { $options['sesskey'] = sesskey(); } foreach ($options as $key => $value) { $optionshtml .= '<input type="hidden" name="' . $key . '" value="' . $value . '" />'; } $class = ''; if ($highlight) { $class = ' class="forumng-highlight"'; } return "<form method='{$method}' action='{$script}' {$class}><div>" . "{$optionshtml}<input type='submit' value='{$name}' />" . "{$extrahtml}</div></form>"; }
function make_discussion($forum, $posts, $readusers, &$userids, $ratingpercent) { set_time_limit(200); // Make discussion static $index = 0; $index++; list($discussionid, $postid) = $forum->create_discussion(null, 'Discussion ' . $index, get_post_text(), FORMAT_HTML, array(), false, 0, 0, false, false, $userids[mt_rand(0, count($userids) - 1)], false); $discussion = forum_discussion::get_from_id($discussionid, forum::CLONE_DIRECT); // Make posts $count = my_random($posts) - 1; $allposts = array($discussion->get_root_post()); for ($i = 0; $i < $count; $i++) { make_post($discussion, $allposts, $userids, $ratingpercent); } // Mark the discussion read if requested if ($readusers > 0) { $now = time(); for ($i = 0; $i < $readusers; $i++) { $discussion->mark_read($now, $userids[$i]); } } // Progress print '.'; }
<?php require_once '../../../../config.php'; require_once $CFG->dirroot . '/mod/forumng/forum.php'; $d = required_param('d', PARAM_INT); $cloneid = optional_param('clone', 0, PARAM_INT); $delete = required_param('delete', PARAM_INT); try { $discussion = forum_discussion::get_from_id($d, $cloneid); $forum = $discussion->get_forum(); $cm = $forum->get_course_module(); $course = $forum->get_course(); // Check permission for change $discussion->require_edit(); // Is this the actual delete? if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($delete) { $discussion->delete(); redirect($forum->get_url(forum::PARAM_PLAIN)); } else { $discussion->undelete(); redirect('../../discuss.php?' . $discussion->get_link_params(forum::PARAM_PLAIN)); } } // Confirm page. Work out navigation for header $pagename = get_string($delete ? 'deletediscussion' : 'undeletediscussion', 'forumng', $discussion->get_subject(false)); $navigation = array(); $navigation[] = array('name' => shorten_text(htmlspecialchars($discussion->get_subject())), 'link' => $discussion->get_url(), 'type' => 'forumng'); $navigation[] = array('name' => $pagename, 'type' => 'forumng'); $PAGEWILLCALLSKIPMAINDESTINATION = true; print_header_simple(format_string($forum->get_name()) . ': ' . $pagename, "", build_navigation($navigation, $cm), "", "", true, '', navmenu($course, $cm));
/** * Displays the discussion page. * @param forum_discussion $discussion Discussion */ public function print_discussion_page($discussion) { $previousread = (int) $discussion->get_time_read(); // 'Read date' option (used when viewing all posts so that they keep // their read/unread colouring) $timeread = optional_param('timeread', 0, PARAM_INT); if ($timeread) { $discussion->pretend_time_read($timeread); $previousread = $timeread; } // 'Expand all' option (always chosen for non-JS browsers) $expandall = optional_param('expand', 0, PARAM_INT) || forum_utils::is_bad_browser(); // 'Expand all' option (always chosen for non-JS browsers) $collapseall = optional_param('collapse', 0, PARAM_INT); // Magic expand tracker (for use in JS only, never set server-side). // This tracks expanded posts, and makes the Back button 'work' in // the sense that it will expand these posts again. print '<form method="post" action="."><div>' . '<input type="hidden" id="expanded_posts" name="expanded_posts" ' . 'value="" /></div></form>'; // Get content for all posts in the discussion $options = array(); if ($expandall) { $options[forum_post::OPTION_CHILDREN_EXPANDED] = true; } if ($collapseall) { $options[forum_post::OPTION_CHILDREN_COLLAPSED] = true; } $content = $this->display_discussion($discussion, $options); // Some post display options use the read time to construct links // (usually for non-JS version) so that unread state is maintained. $options[forum_post::OPTION_READ_TIME] = $previousread; // Display expand all option if there are any 'Expand' links in content $fakedate = '&timeread=' . $previousread; print '<div id="forumng-expandall">'; $showexpandall = preg_match('~<a [^>]*href="discuss\\.php\\?d=[0-9]+[^"]*&expand=1#p[0-9]+">~', $content); $showcollapseall = preg_match('~<div class="forumng-post forumng-full.*<div class="forumng-post forumng-full~s', $content); if ($showexpandall) { print '<a href="' . $discussion->get_url(forum::PARAM_HTML) . '&expand=1' . $fakedate . '">' . get_string('expandall', 'forumng') . '</a>'; if ($showcollapseall) { print ' • '; } } if ($showcollapseall) { print '<a href="' . $discussion->get_url(forum::PARAM_HTML) . '&collapse=1' . $fakedate . '">' . get_string('collapseall', 'forumng') . '</a> '; } print '</div>'; // Display content print $content; // Print reply/edit forms for AJAX print $this->display_ajax_forms($discussion->get_forum()); // Link back to forum print $discussion->display_link_back_to_forum(); // Display discussion features (row of buttons) print $discussion->display_discussion_features(); // Display the subscription options to this disucssion if available print $discussion->display_subscribe_options(); // Atom/RSS links print $discussion->display_feed_links(); // Set read data [shouldn't this logic be somewhere else as it is not // part of display?] if (forum::mark_read_automatically()) { $discussion->mark_read(); } }
$OUMOBILESUPPORT = true; ou_set_is_mobile(ou_get_is_mobile_from_cookies()); } require_once 'forum.php'; if (class_exists('ouflags')) { $DASHBOARD_COUNTER = DASHBOARD_FORUMNG_VIEW; } // Require discussion parameter here. Other parameters may be required in forum // type. $discussionid = required_param('d', PARAM_INT); $cloneid = optional_param('clone', 0, PARAM_INT); try { // Construct discussion variable (will check id is valid) // Retrieve new copy of discussion from database, but store it in cache // for further use. $discussion = forum_discussion::get_from_id($discussionid, $cloneid, 0, false, true); $forum = $discussion->get_forum(); $course = $forum->get_course(); $cm = $forum->get_course_module(); $context = $forum->get_context(); $draftid = optional_param('draft', 0, PARAM_INT); if ($draftid) { $draft = forum_draft::get_from_id($draftid); if (!$draft->is_reply() || $draft->get_discussion_id() != $discussionid) { print_error('draft_mismatch', 'forumng', $forum->get_url(forum::PARAM_HTML)); } $root = $discussion->get_root_post(); $inreplyto = $root->find_child($draft->get_parent_post_id(), false); if (!$inreplyto || !$inreplyto->can_reply($whynot) || !$discussion->can_view()) { print_error('draft_cannotreply', 'forumng', $forum->get_url(forum::PARAM_HTML), get_string($whynot, 'forumng')); }
/** * This function handles all aspects of page processing and then calls * methods in $selector at the appropriate moments. * @param post_selector $selector Object that extends this base class */ static function go($selector) { $d = required_param('d', PARAM_INT); $cloneid = optional_param('clone', 0, PARAM_INT); $fromselect = optional_param('fromselect', 0, PARAM_INT); $all = optional_param('all', '', PARAM_RAW); $select = optional_param('select', '', PARAM_RAW); try { // Get basic objects $discussion = forum_discussion::get_from_id($d, $cloneid); if (optional_param('cancel', '', PARAM_RAW)) { // CALL TYPE 6 redirect('../../discuss.php?' . $discussion->get_link_params(forum::PARAM_PLAIN)); } $forum = $discussion->get_forum(); $cm = $forum->get_course_module(); $course = $forum->get_course(); $isform = optional_param('postselectform', 0, PARAM_INT); // Page name and permissions $pagename = $selector->get_page_name(); $buttonname = $selector->get_button_name(); $discussion->require_view(); $selector->require_capability($forum->get_context(), $discussion); if (!($fromselect || $isform || $all)) { // Either an initial request (non-JS) to display the 'dialog' box, // or a request to show the list of posts with checkboxes for // selection // Both types share same navigation $discussion->print_subpage_header($pagename); if (!$select) { // Show initial dialog print_box_start(); ?> <h2><?php print $buttonname; ?> </h2> <form action="<?php echo $_SERVER['PHP_SELF']; ?> " method="get"><div> <?php print $discussion->get_link_params(forum::PARAM_FORM); ?> <p><?php print_string('selectorall', 'forumng'); ?> </p> <div class="forumng-buttons"> <input type="submit" name="all" value="<?php print_string('discussion', 'forumng'); ?> " /> <input type="submit" name="select" value="<?php print_string('selectedposts', 'forumng'); ?> " /> </div> </div></form> <?php print_box_end(); } else { // Show list of posts to select ?> <div class="forumng-selectintro"> <p><?php print_string('selectintro', 'forumng'); ?> </p> </div> <form action="<?php echo $_SERVER['PHP_SELF']; ?> " method="post"><div> <?php print $discussion->get_link_params(forum::PARAM_FORM); ?> <input type="hidden" name="fromselect" value="1" /> <?php print $forum->get_type()->display_discussion($discussion, array(forum_post::OPTION_NO_COMMANDS => true, forum_post::OPTION_CHILDREN_EXPANDED => true, forum_post::OPTION_SELECTABLE => true)); ?> <div class="forumng-selectoutro"> <input type="submit" value="<?php print_string('confirmselection', 'forumng'); ?> " /> <input type="submit" name="cancel" value="<?php print_string('cancel'); ?> " /> </div> </div></form> <?php } // Display footer print_footer($course); } else { // Call types 3, 4, and 5 use the form (and may include list of postids) if ($all) { $postids = false; } else { $postids = array(); foreach ($_POST as $field => $value) { $matches = array(); if ((string) $value !== '0' && preg_match('~^selectp([0-9]+)$~', $field, $matches)) { $postids[] = $matches[1]; } } } // Get form to use $mform = $selector->get_form($discussion, $all, $postids); if (!$mform) { // Some options do not need a confirmation form; in that case, // just apply the action immediately. $selector->apply($discussion, $all, $postids, null); exit; } // Check cancel if ($mform->is_cancelled()) { redirect('../../discuss.php?' . $discussion->get_link_params(forum::PARAM_PLAIN)); } if ($fromform = $mform->get_data()) { // User submitted form to confirm process, which should now be // applied by selector. $selector->apply($discussion, $all, $postids, $fromform); exit; } else { $discussion->print_subpage_header($pagename); // User requested form either via JavaScript or the other way, and // either with all messages or the whole discussion. // Print form print $mform->display(); // Print optional content that goes after form print $selector->get_content_after_form($discussion, $all, $postids, $fromform); // Display footer print_footer($course); } } } catch (forum_exception $e) { forum_utils::handle_exception($e); } }
/** * Called when displaying a group of posts together on one page. * @param forum_discussion $discussion Forum object * @param string $html HTML that has already been created for the group * of posts * @return string Modified (if necessary) HTML */ public function display_post_group($discussion, $html) { // Add rating form if there are any rating selects $hasratings = strpos($html, '<div class="forumng-editrating">') !== false; $hasflags = strpos($html, '<div class="forumng-flag">') !== false; if ($hasflags || $hasratings) { $script = '<script type="text/javascript">' . 'document.getElementById("forumng-actionform").autocomplete=false;' . '</script>'; $html = '<form method="post" id="forumng-actionform" ' . 'action="action.php"><div>' . $script . $html . $discussion->get_link_params(forum::PARAM_FORM); if ($hasratings) { $html .= '<input type="submit" id="forumng-saveallratings" value="' . get_string('saveallratings', 'forumng') . '" name="action.rate"/>'; } $html .= '</div></form>'; } return $html; }
/** * Either delete or archive old discussions based on the forum setting */ static function archive_old_discussions() { global $CFG; $now = time(); $housekeepingquery = " \nFROM \n {$CFG->prefix}forumng_discussions fd\n INNER JOIN {$CFG->prefix}forumng_posts fp ON fd.lastpostid = fp.id\n INNER JOIN {$CFG->prefix}forumng f ON fd.forumid = f.id\nWHERE\n f.removeafter<>0 AND fd.sticky<>1 AND fp.modified<{$now} - f.removeafter \n"; $count = forum_utils::count_records_sql("SELECT COUNT(1) {$housekeepingquery}"); if ($count) { mtrace("\nBeginning processing {$count} discussion archiving/deleting requests"); $housekeepingrs = forum_utils::get_recordset_sql("\nSELECT \n fd.id AS discussionid, f.id AS forumid, f.removeafter, f.removeto {$housekeepingquery} ORDER BY f.removeto\n "); $targetforum = null; $targetcourseid = null; $cron_log = ''; $discussionmovecount = 0; $discussiondeletecount = 0; while ($rec = rs_fetch_next_record($housekeepingrs)) { $discussion = forum_discussion::get_from_id($rec->discussionid, forum::CLONE_DIRECT); if ($rec->removeto) { //moving to a different forum $forum = $discussion->get_forum(); $course = $forum->get_course(); $modinfo = get_fast_modinfo($course); if ($forum->can_archive_forum($modinfo, $cron_log)) { //Do not get the target forum and course id again if the target forum is the same if (!$targetforum || $targetforum->get_id() != $rec->removeto) { $targetforum = forum::get_from_id($rec->removeto, forum::CLONE_DIRECT); $targetforum = $targetforum->get_real_forum(); } //target discussion groupid must be the same as the original groupid $targetgroupmode = $targetforum->get_group_mode(); $targetgroupid = $targetgroupmode ? $discussion->get_group_id() : null; $discussion->move($targetforum, $targetgroupid); $discussionmovecount++; } } else { //Delete all discussions and relevant data permanently $discussion->permanently_delete(); $discussiondeletecount++; } } rs_close($housekeepingrs); mtrace("\n {$discussionmovecount} discussions have been archived and {$discussiondeletecount} discussions have been deleted permanently."); } }
<?php // Scripts for paste the discussion or cancel the paste. require_once '../../../../config.php'; require_once $CFG->dirroot . '/mod/forumng/forum.php'; $cmid = required_param('cmid', PARAM_INT); $groupid = optional_param('group', forum::NO_GROUPS, PARAM_INT); $cloneid = optional_param('clone', 0, PARAM_INT); try { $targetforum = forum::get_from_cmid($cmid, $cloneid); if (optional_param('cancel', '', PARAM_RAW)) { unset($SESSION->forumng_copyfrom); redirect($targetforum->get_url(forum::PARAM_PLAIN)); } //If the paste action has already been done or cancelled in a different window/tab if (!isset($SESSION->forumng_copyfrom)) { redirect($targetforum->get_url(forum::PARAM_PLAIN)); } $olddiscussionid = $SESSION->forumng_copyfrom; $oldcloneid = $SESSION->forumng_copyfromclone; $olddiscussion = forum_discussion::get_from_id($olddiscussionid, $oldcloneid); // Check permission to copy the discussion require_capability('mod/forumng:copydiscussion', $olddiscussion->get_forum()->get_context()); //security check to see if can start a new discussion in the target forum $targetforum->require_start_discussion($groupid); $olddiscussion->copy($targetforum, $groupid); unset($SESSION->forumng_copyfrom); redirect($targetforum->get_url(forum::PARAM_PLAIN)); } catch (forum_exception $e) { forum_utils::handle_exception($e); }
/** * Merges the contents of this discussion into another discussion. * @param forum_discussion $targetdiscussion Target discussion * @param int $userid User ID (0 = current) * @param bool $log True to log this action */ public function merge_into($targetdiscussion, $userid = 0, $log = true) { global $CFG; forum_utils::start_transaction(); // Update parent post id of root post $record = new stdClass(); $record->id = $this->discussionfields->postid; $record->parentpostid = $targetdiscussion->discussionfields->postid; forum_utils::update_record('forumng_posts', $record); // Move all posts into new discussion forum_utils::execute_sql("UPDATE {$CFG->prefix}forumng_posts SET " . "discussionid=" . $targetdiscussion->get_id() . " WHERE discussionid=" . $this->get_id()); // Delete this discussion forum_utils::delete_records('forumng_discussions', 'id', $this->discussionfields->id); // Merge attachments (if any) $oldfolder = $this->get_attachment_folder(); $newfolder = $targetdiscussion->get_attachment_folder(); if (is_dir($oldfolder)) { $handle = forum_utils::opendir($oldfolder); $madenewfolder = false; while (false !== ($name = readdir($handle))) { if ($name != '.' && $name != '..') { if (!$madenewfolder) { check_dir_exists($newfolder, true, true); $madenewfolder = true; } $oldname = $oldfolder . '/' . $name; $newname = $newfolder . '/' . $name; forum_utils::rename($oldname, $newname); } } closedir($handle); } // Merging the discussion into another might cause completion changes // (if there was a requirement for discussions and this is no longer // a discussion in its own right). $this->update_completion(false); if ($log) { $this->log('merge discussion d' . $targetdiscussion->get_id()); } forum_utils::finish_transaction(); $this->uncache(); $targetdiscussion->uncache(); }
/** * Obtains list of posts to include in an Atom/RSS feed. * @param int $groupid Group ID (may be ALL_GROUPS) * @param int $userid User ID * @param forum_discussion $discussion Discussion object (intended only * for calls via the forum_discussion method) * @return array Array of forum_post objects */ public function get_feed_posts($groupid, $userid, $discussion = null) { // Don't let user view any posts in a discussion feed they can't see // (I don't think they should be given a key in this case, but just // to be sure). if ($discussion && !$this->get_type()->can_view_discussion($discussion, $userid)) { return array(); } // Number of items to output $items = $this->get_effective_feed_items(); // Get most recent N posts from db if ($discussion) { $where = 'fd.id=' . $discussion->get_id(); } else { $where = 'fd.forumid=' . $this->get_id(); if ($this->get_group_mode() && $groupid != self::ALL_GROUPS) { $where .= ' AND fd.groupid=' . $groupid; } } // Don't include deleted or old-version posts $where .= ' AND fp.oldversion=0 AND fp.deleted=0 AND fd.deleted=0'; // Or ones out of time $now = time(); $where .= " AND (fd.timestart < {$now})" . " AND (fd.timeend = 0 OR fd.timeend > {$now})"; $postrecs = forum_post::query_posts($where, 'GREATEST(fp.created, fd.timestart) DESC', false, false, false, $userid, true, false, 0, $items); if (count($postrecs) == 0) { // No posts! return array(); } $result = array(); if ($discussion) { foreach ($postrecs as $rec) { $post = new forum_post($discussion, $rec, null); $result[$rec->id] = $post; } } else { // Based on these posts, get all mentioned discussions $discussionids = array(); $discussionposts = array(); foreach ($postrecs as $rec) { $discussionids[] = $rec->discussionid; $discussionposts[$rec->discussionid][] = $rec->id; } $discussionpart = forum_utils::in_or_equals($discussionids); $rs = forum_discussion::query_discussions("fd.id " . $discussionpart, -1, 'id'); // Build the discussion and post objects $posts = array(); while ($rec = rs_fetch_next_record($rs)) { $discussion = new forum_discussion($this, $rec, true, -1); if ($discussion->can_view($userid)) { foreach ($discussionposts[$discussion->get_id()] as $postid) { $post = new forum_post($discussion, $postrecs[$postid], null); $posts[$postid] = $post; } } } rs_close($rs); // Put them back in order of the post records, and return foreach ($postrecs as $rec) { // Records might be excluded if user can't view discussion if (array_key_exists($rec->id, $posts)) { $result[$rec->id] = $posts[$rec->id]; } } } return $result; }
$discussion = forum_discussion::get_from_id($d, $cloneid); $forum = $discussion->get_forum(); $cm = $forum->get_course_module(); $course = $forum->get_course(); // Require that you can see this discussion (etc) and merge them $discussion->require_view(); if (!$discussion->can_split($whynot)) { print_error($whynot, 'forumng'); } if ($stage == 2) { if (!confirm_sesskey()) { print_error('invalidsesskey'); } if (!isset($_POST['cancel'])) { // Get source discussion and check permissions $sourcediscussion = forum_discussion::get_from_id($SESSION->forumng_mergefrom, $SESSION->forumng_mergefromclone); $sourcediscussion->require_view(); if (!$sourcediscussion->can_split($whynot)) { print_error($whynot, 'forumng'); } // Do actual merge $sourcediscussion->merge_into($discussion); } unset($SESSION->forumng_mergefrom); redirect('../../discuss.php?' . $discussion->get_link_params(forum::PARAM_PLAIN)); } // Create form require_once 'merge_form.php'; $mform = new mod_forumng_merge_form('merge.php', array('d' => $d, 'clone' => $cloneid)); if ($mform->is_cancelled()) { redirect('../../discuss.php?' . $discussion->get_link_params(forum::PARAM_PLAIN));
/** * Calls search_update on each child of the current post, and recurses. * Used when the subject's discussion is changed. */ function search_update_children() { if (!forum::search_installed()) { return; } // If the in-memory post object isn't already part of a full // discussion... if (!is_array($this->children)) { // ...then get one $discussion = forum_discussion::get_from_id($this->discussion->get_id(), $this->get_forum()->get_course_module_id()); $post = $discussion->get_root_post()->find_child($this->get_id()); // Do this update on the new discussion $post->search_update_children(); return; } // Loop through all children foreach ($this->children as $child) { // Update its search fields $child->search_update(); // Recurse $child->search_update_children(); } }