public function get_unread_restriction_sql($forum, $userid = 0)
 {
     $userid = forum_utils::get_real_userid($userid);
     // See if they're already allowed to view all discussions
     if ($forum->can_view_hidden($userid)) {
         return '';
     }
     // Otherwise restrict it
     return 'fpfirst.userid=' . $userid;
 }
/**
 * Return a list of groups the user belongs to that apply to this forum (same grouping)
 * @param int $userid
 * @param int $forumid
 * @return an array of group lists or an empty array
 */
function get_group_list($userid, $forumid)
{
    global $CFG;
    //$courseid = forum::get_from_id($forumng->id, forum::CLONE_DIRECT)->get_course_id();
    $sql_group = "\nSELECT\n    g.id AS groupid\nFROM\n    {$CFG->prefix}forumng f\n    INNER JOIN {$CFG->prefix}course_modules cm on f.id = cm.instance \n    INNER JOIN {$CFG->prefix}modules m on cm.module = m.id \n    INNER JOIN {$CFG->prefix}groups_members gm ON gm.userid = {$userid} \n    INNER JOIN {$CFG->prefix}groups g ON gm.groupid = g.id AND g.courseid = cm.course \n    LEFT JOIN {$CFG->prefix}groupings_groups gg ON gg.groupid = g.id AND cm.groupingid = gg.groupingid \nWHERE\n    f.id = {$forumid}\n    AND m.name = 'forumng'\n    AND (cm.groupingid = 0 or gg.id IS NOT NULL)";
    $rs = forum_utils::get_recordset_sql($sql_group);
    $results = array();
    while ($rec = rs_fetch_next_record($rs)) {
        $results[] = $rec->groupid;
    }
    rs_close($rs);
    return $results;
}
 function definition()
 {
     global $CFG, $USER;
     $mform = $this->_form;
     $course = $this->_customdata;
     // Query for supported forums
     $forums = forum_utils::get_convertible_forums($course);
     $forumoptions = array();
     foreach ($forums as $forum) {
         $forumoptions[$forum->id] = $forum->name;
     }
     $mform->addElement('static', '', '', get_string('convert_info', 'forumng'));
     $select = $mform->addElement('select', 'forums', get_string('modulenameplural', 'forum'), $forumoptions);
     $select->setMultiple(true);
     $mform->addElement('checkbox', 'nodata', '', get_string('convert_nodata', 'forumng'));
     $mform->addElement('static', '', '', get_string('convert_warning', 'forumng'));
     $mform->addElement('checkbox', 'hide', '', get_string('convert_hide', 'forumng'));
     $this->add_action_buttons(true, get_string('convert_title', 'forumng'));
     $mform->addElement('hidden', 'course', $this->_customdata->id);
 }
    if (!$courseid) {
        $courseid = $forum->get_course()->id;
    }
    redirect('index.php?id=' . $courseid);
}
if ($back == 'view') {
    redirect($forum->get_url(mod_forumng::PARAM_PLAIN));
}
if ($back == 'discuss') {
    redirect('discuss.php?' . $discussion->get_link_params(mod_forumng::PARAM_PLAIN));
}
// Not redirecting? OK, confirm
if ($cmid || $discussionid) {
    $backurl = $forum->get_url(mod_forumng::PARAM_HTML);
    $out = $forum->init_page($pageurl, get_string($subscribe ? 'subscribeshort' : 'unsubscribeshort', 'forumng'));
    print $out->header();
    print $out->notification($confirmtext, 'notifysuccess');
    print $out->continue_button($backurl);
    print $out->footer();
} else {
    $backurl = $CFG->wwwroot . '/course/view.php?id=' . $courseid;
    $PAGE->set_url($pageurl);
    $PAGE->set_context(context_course::instance($courseid));
    $PAGE->set_heading($COURSE->fullname);
    $PAGE->set_title($COURSE->shortname);
    $out = forum_utils::get_renderer();
    print $out->header();
    print $out->notification($confirmtext, 'notifysuccess');
    print $out->continue_button($backurl);
    print $out->footer();
}
 function definition()
 {
     global $CFG, $COURSE;
     $mform =& $this->_form;
     $coursecontext = get_context_instance(CONTEXT_COURSE, $COURSE->id);
     $forumng = $this->_instance ? get_record('forumng', 'id', $this->_instance) : null;
     $this->clone = $forumng ? $forumng->originalcmid : 0;
     // If this is a clone, don't show the normal form
     if ($this->clone) {
         $mform->addElement('hidden', 'name', $forumng->name);
         $mform->addElement('static', 'sharedthing', '', get_string('sharedinfo', 'forumng', $CFG->wwwroot . '/course/modedit.php?update=' . $this->clone . '&return=1'));
         $this->shared_definition_part($coursecontext);
         return;
     }
     $mform->addElement('header', 'general', get_string('general', 'form'));
     // Forum name
     $mform->addElement('text', 'name', get_string('forumname', 'forumng'), array('size' => '64'));
     if (!empty($CFG->formatstringstriptags)) {
         $mform->setType('name', PARAM_TEXT);
     } else {
         $mform->setType('name', PARAM_CLEAN);
     }
     $mform->addRule('name', null, 'required', null, 'client');
     $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
     // Forum types
     $types = forum_type::get_all();
     $options = array();
     foreach ($types as $type) {
         if ($type->is_user_selectable()) {
             $options[$type->get_id()] = $type->get_name();
         }
     }
     $mform->addElement('select', 'type', get_string('forumtype', 'forumng'), $options);
     $mform->setHelpButton('type', array('forumtype', get_string('forumtype', 'forumng'), 'forumng'));
     $mform->setDefault('type', 'general');
     $mform->addElement('htmleditor', 'intro', get_string('forumintro', 'forumng'));
     $mform->setType('intro', PARAM_RAW);
     $mform->setHelpButton('intro', array('writing', 'questions', 'richtext'), false, 'editorhelpbutton');
     // Subscription option displays only if enabled at site level
     if ($CFG->forumng_subscription == -1) {
         $options = forum::get_subscription_options();
         $mform->addElement('select', 'subscription', get_string('subscription', 'forumng'), $options);
         $mform->setDefault('subscription', forum::SUBSCRIPTION_PERMITTED);
         $mform->setHelpButton('subscription', array('subscription', get_string('subscription', 'forumng'), 'forumng'));
     } else {
         // Hidden element contains default value (not used anyhow)
         $mform->addElement('hidden', 'subscription', forum::SUBSCRIPTION_PERMITTED);
     }
     // Max size of attachments
     $choices = get_max_upload_sizes($CFG->maxbytes, $COURSE->maxbytes);
     $choices[-1] = get_string('uploadnotallowed');
     $choices[0] = get_string('courseuploadlimit') . ' (' . display_size($COURSE->maxbytes) . ')';
     $mform->addElement('select', 'attachmentmaxbytes', get_string('attachmentmaxbytes', 'forumng'), $choices);
     $mform->setHelpButton('attachmentmaxbytes', array('attachmentmaxbytes', get_string('attachmentmaxbytes', 'forumng'), 'forumng'));
     $mform->setDefault('attachmentmaxbytes', $CFG->forumng_attachmentmaxbytes);
     //Email address for reporting unacceptable post for this forum, default is blank
     $mform->addElement('text', 'reportingemail', get_string('reportingemail', 'forumng'), array('size' => 48));
     $mform->setType('reportingemail', PARAM_NOTAGS);
     $mform->setHelpButton('reportingemail', array('reportingemail', get_string('reportingemail', 'forumng'), 'forumng'));
     // Atom/RSS feed on/off/discussions-only
     if ($CFG->enablerssfeeds && !empty($CFG->forumng_enablerssfeeds)) {
         if ($CFG->forumng_feedtype == -1 || $CFG->forumng_feeditems == -1) {
             $mform->addElement('header', '', get_string('feeds', 'forumng'));
         }
         if ($CFG->forumng_feedtype == -1) {
             $mform->addElement('select', 'feedtype', get_string('feedtype', 'forumng'), forum::get_feedtype_options());
             $mform->setDefault('feedtype', forum::FEEDTYPE_ALL_POSTS);
             $mform->setHelpButton('feedtype', array('feedtype', get_string('feedtype', 'forumng'), 'forumng'));
         }
         // Atom/RSS feed item count
         if ($CFG->forumng_feeditems == -1) {
             $mform->addElement('select', 'feeditems', get_string('feeditems', 'forumng'), forum::get_feeditems_options());
             $mform->setDefault('feeditems', 20);
             $mform->setHelpButton('feeditems', array('feeditems', get_string('feeditems', 'forumng'), 'forumng'));
         }
     }
     // Ratings header
     /////////////////
     $mform->addElement('header', '', get_string('ratings', 'forumng'));
     $mform->addElement('checkbox', 'enableratings', get_string('enableratings', 'forumng'));
     $mform->setHelpButton('enableratings', array('enableratings', get_string('enableratings', 'forumng'), 'forumng'));
     // Scale
     $mform->addElement('modgrade', 'ratingscale', get_string('scale'), null, true);
     $mform->disabledIf('ratingscale', 'enableratings', 'notchecked');
     $mform->setDefault('ratingscale', 5);
     // From/until times
     $mform->addElement('date_time_selector', 'ratingfrom', get_string('ratingfrom', 'forumng'), array('optional' => true));
     $mform->disabledIf('ratingfrom', 'enableratings', 'notchecked');
     $mform->addElement('date_time_selector', 'ratinguntil', get_string('ratinguntil', 'forumng'), array('optional' => true));
     $mform->disabledIf('ratinguntil', 'enableratings', 'notchecked');
     $mform->addElement('text', 'ratingthreshold', get_string('ratingthreshold', 'forumng'));
     $mform->setType('ratingthreshold', PARAM_INT);
     $mform->setDefault('ratingthreshold', 1);
     $mform->addRule('ratingthreshold', get_string('error_ratingthreshold', 'forumng'), 'regex', '/[1-9][0-9]*/', 'client');
     $mform->setHelpButton('ratingthreshold', array('ratingthreshold', get_string('ratingthreshold', 'forumng'), 'forumng'));
     $mform->disabledIf('ratingthreshold', 'enableratings', 'notchecked');
     // Grading
     $mform->addElement('select', 'grading', get_string('grade'), forum::get_grading_options());
     $mform->setDefault('grading', forum::GRADING_NONE);
     $mform->setHelpButton('grading', array('grading', get_string('grade'), 'forumng'));
     $mform->disabledIf('grading', 'enableratings', 'notchecked');
     // Blocking header
     //////////////////
     $mform->addElement('header', '', get_string('limitposts', 'forumng'));
     // Post dates
     $mform->addElement('date_time_selector', 'postingfrom', get_string('postingfrom', 'forumng'), array('optional' => true));
     $mform->addElement('date_time_selector', 'postinguntil', get_string('postinguntil', 'forumng'), array('optional' => true));
     // User limits
     $limitgroup = array();
     $limitgroup[] = $mform->createElement('checkbox', 'enablelimit', '');
     $options = forum::get_max_posts_period_options();
     $limitgroup[] = $mform->createElement('text', 'maxpostsblock', '', array('size' => 3));
     $limitgroup[] = $mform->createElement('static', 'staticthing', '', ' ' . get_string('postsper', 'forumng') . ' ');
     $limitgroup[] = $mform->createElement('select', 'maxpostsperiod', '', $options);
     $mform->addGroup($limitgroup, 'limitgroup', get_string('enablelimit', 'forumng'));
     $mform->disabledIf('limitgroup[maxpostsblock]', 'limitgroup[enablelimit]');
     $mform->disabledIf('limitgroup[maxpostsperiod]', 'limitgroup[enablelimit]');
     $mform->setHelpButton('limitgroup', array('enablelimit', get_string('enablelimit', 'forumng'), 'forumng'));
     $mform->setType('limitgroup[maxpostsblock]', PARAM_INT);
     $mform->setDefault('limitgroup[maxpostsblock]', '10');
     // Remove old discussion
     $options = array();
     $options[0] = get_string('removeolddiscussionsdefault', 'forumng');
     for ($i = 1; $i <= 36; $i++) {
         $options[$i * 2592000] = $i;
     }
     $mform->addElement('header', '', get_string('removeolddiscussions', 'forumng'));
     $mform->addElement('select', 'removeafter', get_string('removeolddiscussionsafter', 'forumng'), $options);
     $mform->setHelpButton('removeafter', array('removeolddiscussions', get_string('removeolddiscussions', 'forumng'), 'forumng'));
     $options = array();
     $options[0] = get_string('deletepermanently', 'forumng');
     $modinfo = get_fast_modinfo($COURSE);
     $targetforumid = $this->_instance ? $this->_instance : 0;
     // Add all in stances to drop down if the user can access them and it's not the same as the current forum
     if (array_key_exists('forumng', $modinfo->instances)) {
         foreach ($modinfo->instances['forumng'] as $info) {
             if ($info->uservisible && $targetforumid != $info->instance) {
                 $options[$info->instance] = $info->name;
             }
         }
     }
     $mform->addElement('select', 'removeto', get_string('withremoveddiscussions', 'forumng'), $options);
     $mform->disabledIf('removeto', 'removeafter', 'eq', 0);
     $mform->setHelpButton('removeto', array('withremoveddiscussions', get_string('withremoveddiscussions', 'forumng'), 'forumng'));
     // Sharing options are advanced and for administrators only
     if ($CFG->forumng_enableadvanced && has_capability('moodle/site:config', $coursecontext)) {
         $mform->addElement('header', '', get_string('sharing', 'forumng'));
         $mform->addElement('advcheckbox', 'shared', get_string('shared', 'forumng'));
         $mform->setHelpButton('shared', array('shared', get_string('shared', 'forumng'), 'forumng'));
         // Only when creating a forum, you can choose to make it a clone
         if (!$this->_instance) {
             $sharegroup = array();
             $sharegroup[] = $mform->createElement('checkbox', 'useshared', '');
             $sharegroup[] = $mform->createElement('text', 'originalcmidnumber', '');
             $mform->addGroup($sharegroup, 'usesharedgroup', get_string('useshared', 'forumng'));
             $mform->disabledIf('usesharedgroup[originalcmidnumber]', 'usesharedgroup[useshared]', 'notchecked');
             $mform->setHelpButton('usesharedgroup', array('useshared', get_string('useshared', 'forumng'), 'forumng'));
         }
     }
     // Do definition that is shared with clone version of form
     $this->shared_definition_part($coursecontext);
     if (count(forum_utils::get_convertible_forums($COURSE)) > 0 && !$this->_instance) {
         $mform->addElement('static', '', '', '<div class="forumng-convertoffer">' . get_string('offerconvert', 'forumng', $CFG->wwwroot . '/mod/forumng/convert.php?course=' . $COURSE->id) . '</div>');
     }
 }
 private function mark_mailed($time)
 {
     global $CFG;
     $querychunk = $this->get_query_chunk($time, 'forumng_posts');
     $before = microtime(true);
     mtrace('Marking processed posts: ', '');
     forum_utils::update_with_subquery_grrr_mysql("\nUPDATE\n    {$CFG->prefix}forumng_posts\nSET\n    mailstate = " . $this->get_target_mail_state() . "\nWHERE\n    id %'IN'%", "SELECT fp.id {$querychunk}");
     mtrace(round(microtime(true) - $before, 1) . 's.');
     unset_config($this->get_pending_flag_name(), 'forumng');
 }
function make_students($courseid, $count)
{
    print "<h3>Making {$count} students</h3><pre>";
    $time = time();
    forum_utils::start_transaction();
    for ($i = 0; $i < $count; $i++) {
        make_student($courseid, $time . '_' . $i);
        print '.';
        if (($i + 1) % 20 == 0) {
            print " (" . ($i + 1) . ")\n";
        }
        flush();
    }
    forum_utils::finish_transaction();
    print "</pre>";
}
/**
 * Get search results.
 * @param object $course
 * @param string $author
 * @param int $daterangefrom
 * @param int $daterangeto
 * @param int $page
 * @param int $resultsperpage (FORUMNG_SEARCH_RESULTSPERPAGE used as constant)
 * @return object
 */
function forumng_get_results_for_all_forums($course, $author = null, $daterangefrom = 0, $daterangeto = 0, $page, $resultsperpage = FORUMNG_SEARCH_RESULTSPERPAGE)
{
    $before = microtime(true);
    global $CFG, $USER;
    // Get all forums
    $modinfo = get_fast_modinfo($course);
    $visibleforums = array();
    $accessallgroups = array();
    foreach ($modinfo->cms as $cmid => $cm) {
        if ($cm->modname === 'forumng' && $cm->uservisible) {
            $visibleforums[$cm->instance] = $cm->groupmode;
            // Check access all groups for this forum, if they have it, add to list
            //$forum = forum::get_from_cmid($cm->id, 0);
            $forum = forum::get_from_id($cm->instance, 0);
            if ($forum->get_group_mode() == SEPARATEGROUPS) {
                if (has_capability('moodle/site:accessallgroups', $forum->get_context())) {
                    $accessallgroups[] = $cm->instance;
                }
            }
        }
    }
    $forumids = array_keys($visibleforums);
    $separategroupsforumids = array_keys($visibleforums, SEPARATEGROUPS);
    $inforumids = forum_utils::in_or_equals($forumids);
    $inseparategroups = forum_utils::in_or_equals($separategroupsforumids);
    $inaccessallgroups = forum_utils::in_or_equals($accessallgroups);
    $where = "WHERE d.forumid {$inforumids}";
    $where .= " AND (NOT (d.forumid {$inseparategroups})";
    $where .= " OR d.forumid {$inaccessallgroups}";
    $where .= " OR gm.id IS NOT NULL";
    $where .= " OR d.groupid IS NULL)";
    // Note: Even if you have capability to view the deleted or timed posts,
    // we don't show them for consistency with the full-text search.
    $currenttime = time();
    $where .= " AND ({$currenttime} >= d.timestart OR d.timestart = 0)";
    $where .= " AND ({$currenttime} < d.timeend OR d.timeend = 0)";
    //exclude older post versions
    $where .= " AND p.oldversion=0 ";
    $where .= " AND d.deleted=0 AND p.deleted=0 ";
    if ($author) {
        $where .= forumng_get_author_sql($author);
    }
    if ($daterangefrom && !is_array($daterangefrom)) {
        $where .= " AND p.modified>={$daterangefrom}";
    }
    if ($daterangeto && !is_array($daterangeto)) {
        $where .= " AND p.modified<={$daterangeto}";
    }
    $sql = "SELECT p.modified, p.id, p.discussionid, gm.id AS useringroup, p.userid, p.parentpostid, \n            p.subject AS title, p.message AS summary, u.username, u.firstname, \n            u.lastname, d.forumid, d.groupid, d.postid AS discussionpostid\n            FROM {$CFG->prefix}forumng_posts p\n            INNER JOIN {$CFG->prefix}forumng_discussions d ON d.id = p.discussionid\n            INNER JOIN {$CFG->prefix}user u ON p.userid = u.id\n            LEFT JOIN {$CFG->prefix}groups_members gm ON gm.groupid = d.groupid AND gm.userid = {$USER->id}\n            {$where}\n            ORDER BY p.modified DESC, p.id ASC";
    $results = new stdClass();
    $results->success = 1;
    $results->numberofentries = 0;
    $results->done = 0;
    if (!($posts = get_records_sql($sql, $page, $resultsperpage))) {
        $posts = array();
    }
    foreach ($posts as $post) {
        if (!$post->title) {
            // Ideally we would get the parent post that has a subject, but
            // this could involve a while loop that might make numeroous
            // queries, so instead, let's just use the discussion subject
            $post->title = get_string('re', 'forumng', get_field('forumng_posts', 'subject', 'id', $post->discussionpostid));
        }
        $post->title = s(strip_tags($post->title));
        $post->summary = s(strip_tags(shorten_text($post->summary, 250)));
        $post->url = $CFG->wwwroot . "/mod/forumng/discuss.php?d={$post->discussionid}#p{$post->id}";
    }
    $results->results = $posts;
    $results->searchtime = microtime(true) - $before;
    $results->numberofentries = count($results->results);
    if (count($results->results) < $resultsperpage) {
        $results->done = 1;
    } elseif (!($extrapost = get_records_sql($sql, $page + $resultsperpage, 1))) {
        $results->done = 1;
    }
    return $results;
}
 /**
  * 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 = '&amp;timeread=' . $previousread;
     print '<div id="forumng-expandall">';
     $showexpandall = preg_match('~<a [^>]*href="discuss\\.php\\?d=[0-9]+[^"]*&amp;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) . '&amp;expand=1' . $fakedate . '">' . get_string('expandall', 'forumng') . '</a>';
         if ($showcollapseall) {
             print ' &#x2022; ';
         }
     }
     if ($showcollapseall) {
         print '<a href="' . $discussion->get_url(forum::PARAM_HTML) . '&amp;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();
     }
 }
    /**
     * 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);
        }
    }
 /**
  * Executes a database update in such a way that it will work in MySQL,
  * when the update uses a subquery that refers to the table being updated.
  * @param string $update Update query with the special string %'IN'% at the
  *   point where the IN clause should go, i.e. replacing 'IN (SELECT id ...)' 
  * @param string $inids Query that selects a column (which must be named
  *   id), i.e. 'SELECT id ...'
  */
 public static function update_with_subquery_grrr_mysql($update, $inids)
 {
     global $CFG;
     if (preg_match('~^mysql~', $CFG->dbtype)) {
         // MySQL is a PoS so the update can't directly run (you can't update
         // a table based on a subquery that refers to the table). Instead,
         // we do the same thing but with a separate update using an IN clause.
         // This might theoretically run into problems if you had a really huge
         // set of forums with frequent posts (so that the IN size exceeds
         // MySQL query limit) however the limits appear to be generous enough
         // that this is unlikely.
         $ids = array();
         $rs = forum_utils::get_recordset_sql($inids);
         while ($rec = rs_fetch_next_record($rs)) {
             $ids[] = $rec->id;
         }
         rs_close($rs);
         if (count($ids) > 0) {
             $update = str_replace("%'IN'%", forum_utils::in_or_equals($ids), $update);
             forum_utils::execute_sql($update);
         }
     } else {
         // With a decent database we can do the update and query in one,
         // avoiding the need to transfer an ID list around.
         forum_utils::execute_sql(str_replace("%'IN'%", "IN ({$inids})", $update));
     }
 }
 /**
  * Gets URL for an Atom/RSS feed to this discussion.
  * @param int $feedformat FEEDFORMAT_xx constant
  * @param int $userid User ID or 0 for current
  * @return string URL for feed
  */
 public function get_feed_url($feedformat, $userid = 0)
 {
     global $CFG;
     $userid = forum_utils::get_real_userid($userid);
     $groupid = $this->get_group_id();
     return $CFG->wwwroot . '/mod/forumng/feed.php?' . $this->get_link_params(forum::PARAM_PLAIN) . '&user='******'&key=' . $this->get_forum()->get_feed_key($groupid, $userid) . '&format=' . ($feedformat == forum::FEEDFORMAT_RSS ? 'rss' : 'atom');
 }
 /**
  * Update the forumng_subscription table to incorporate the group subscription feature.
  * @param bool $moodleupdate If this is true, the function is running as part of the 
  *   moodle upgrade.php for Sep 2010 release. In this case, the database queries must
  *   not be changed and other code must work the same way (avoid calls to functions
  *   except Moodle standard ones)
  */
 public function group_subscription_update($moodleupdate = false, $cmid = 0)
 {
     global $CFG;
     forum_utils::start_transaction();
     if ($cmid) {
         //only update one forum
         $optionalquery = "AND cm.id = {$cmid}";
     } else {
         $optionalquery = '';
     }
     // Query get the distinct forums
     $sql_count = "\nSELECT\n    COUNT(DISTINCT cm.id) AS totalnumberforum\nFROM \n    {$CFG->prefix}forumng_subscriptions fs\n    INNER JOIN {$CFG->prefix}course_modules cm on fs.forumid = cm.instance \n    INNER JOIN {$CFG->prefix}modules m on cm.module = m.id \n    INNER JOIN {$CFG->prefix}course c on c.id = cm.course \nWHERE \n    discussionid IS NULL AND m.name='forumng' {$optionalquery}\n    AND (CASE WHEN c.groupmodeforce=1 THEN c.groupmode ELSE cm.groupmode END ) = 1";
     //Query lists all subscriptions to forums that have separate groups
     $sql_sub = "\nSELECT\n    cm.id AS cmid, fs.id AS subid, fs.userid, fs.forumid, c.id AS courseid, cm.groupingid \nFROM\n    {$CFG->prefix}forumng_subscriptions fs\n    INNER JOIN {$CFG->prefix}course_modules cm on fs.forumid = cm.instance \n    INNER JOIN {$CFG->prefix}modules m on cm.module = m.id \n    INNER JOIN {$CFG->prefix}course c on c.id = cm.course \nWHERE \n    discussionid IS NULL and m.name='forumng' {$optionalquery}\n    AND (CASE WHEN c.groupmodeforce=1 THEN c.groupmode ELSE cm.groupmode END ) = 1 \nORDER BY cm.id, fs.id";
     //Query lists all groups that the user belongs to from the above query
     $sql_group = "\nSELECT\n    subs.subid, g.id AS groupid\nFROM\n    ({$sql_sub}) subs \n    INNER JOIN {$CFG->prefix}groups_members gm ON gm.userid = subs.userid \n    INNER JOIN {$CFG->prefix}groups g ON gm.groupid = g.id AND g.courseid = subs.courseid \n    LEFT JOIN {$CFG->prefix}groupings_groups gg ON gg.groupid = g.id AND subs.groupingid = gg.groupingid \nWHERE\n    (subs.groupingid = 0 or gg.id IS NOT NULL)\nORDER BY\n    subs.cmid, subs.subid";
     $rs = forum_utils::get_recordset_sql($sql_group);
     $results = array();
     while ($rec = rs_fetch_next_record($rs)) {
         if (!array_key_exists($rec->subid, $results)) {
             $results[$rec->subid] = array();
         }
         $results[$rec->subid][] = $rec->groupid;
     }
     rs_close($rs);
     $rs = forum_utils::get_recordset_sql($sql_sub);
     $lastcmid = 0;
     $forumcount = 1;
     $totalforumcount = 0;
     $totalforumcount = count_records_sql($sql_count);
     while ($rec = rs_fetch_next_record($rs)) {
         if ($lastcmid != $rec->cmid) {
             if ($moodleupdate) {
                 print "Updating the subscriptions {$forumcount}/{$totalforumcount} (current cmid:{$rec->cmid}) <br />";
             }
             $context = get_context_instance(CONTEXT_MODULE, $rec->cmid);
             $aagusers = get_users_by_capability($context, 'moodle/site:accessallgroups', 'u.id');
             $aagusers = $aagusers ? $aagusers : array();
             $lastcmid = $rec->cmid;
             $forumcount++;
         }
         if (!array_key_exists($rec->userid, $aagusers)) {
             //Delete the whole forum subscription
             forum_utils::delete_records('forumng_subscriptions', 'id', $rec->subid);
             //check if the subid exists in the results array
             if (array_key_exists($rec->subid, $results)) {
                 foreach ($results[$rec->subid] as $groupid) {
                     $subrecord = new StdClass();
                     $subrecord->userid = $rec->userid;
                     $subrecord->forumid = $rec->forumid;
                     $subrecord->subscribed = 1;
                     $subrecord->groupid = $groupid;
                     forum_utils::insert_record('forumng_subscriptions', $subrecord);
                 }
             }
         }
     }
     forum_utils::finish_transaction();
 }
 /**
  * Checks whether the user can edit the post, assuming that they can
  * view the discussion.
  * @param string &$whynot If returning false, set to the language string defining
  *   reason for not being able to edit
  * @param int $userid User ID or 0 if current
  * @return bool True if user can edit this post
  */
 function can_edit(&$whynot, $userid = 0)
 {
     global $CFG;
     $userid = forum_utils::get_real_userid($userid);
     $context = $this->get_forum()->get_context();
     // Check if post is a special case
     if ($this->get_deleted() || $this->is_old_version() || $this->get_discussion()->is_deleted()) {
         $whynot = 'edit_notcurrentpost';
         return false;
     }
     // Check if discussion is different group
     if (!$this->get_discussion()->can_write_to_group()) {
         $whynot = 'edit_wronggroup';
         return false;
     }
     // Check if discussion is locked
     if ($this->get_discussion()->is_locked()) {
         $whynot = 'edit_locked';
         return false;
     }
     // Check the 'edit any' capability
     $editanypost = has_capability('mod/forumng:editanypost', $context, $userid);
     if (!$editanypost) {
         // If they don't have edit any, they must have either the
         // 'start discussion' or 'reply post' capability (the same
         // one they needed to create the post in the first place)
         if ($this->is_root_post() && !has_capability('mod/forumng:startdiscussion', $context, $userid) && (!$this->is_root_post() && !has_capability('mod/forumng:replypost', $context, $userid))) {
             $whynot = 'edit_nopermission';
             return false;
         }
     }
     // Check post belongs to specified user
     if ($this->get_user()->id != $userid && !$editanypost) {
         $whynot = 'edit_notyours';
         return false;
     }
     // Check editing timeout
     if (time() > $this->get_edit_time_limit() && !$editanypost) {
         $whynot = 'edit_timeout';
         return false;
     }
     // Check read-only dates
     if ($this->get_forum()->is_read_only($userid)) {
         $whynot = 'edit_readonly';
         return false;
     }
     // OK! They're allowed to edit (whew)
     $whynot = '';
     return true;
 }
function forumng_decode_content_links_caller($restore)
{
    // Get all the items that might have links in, from the relevant new course
    try {
        global $CFG, $db;
        // 1. Intros
        if ($intros = get_records_select('forumng', 'course=' . $restore->course_id . ' AND intro IS NOT NULL', '', 'id, intro, name')) {
            foreach ($intros as $intro) {
                $newintro = $intro->intro;
                // Special behaviour hidden in intro
                $matches = array();
                if (preg_match('~%%CMIDNUMBER:([^%]+)%%$~', $newintro, $matches)) {
                    $newintro = substr($newintro, 0, -strlen($matches[0]));
                    $idnumber = $matches[1];
                    $cm = forum::get_shared_cm_from_idnumber($idnumber);
                    if ($cm) {
                        set_field('forumng', 'originalcmid', $cm->id, 'id', $intro->id);
                    } else {
                        // The original forum cannot be found, so restore
                        // this as not shared
                        if (!defined('RESTORE_SILENTLY')) {
                            $a = (object) array('name' => s($intro->name), 'idnumber' => s($idnumber));
                            print '<br />' . get_string('error_nosharedforum', 'forumng', $a) . '<br />';
                        }
                    }
                }
                if (preg_match('~%%REMOVETHIS%%$~', $newintro)) {
                    $newintro = substr($newintro, 0, -14);
                }
                $newintro = restore_decode_content_links_worker($newintro, $restore);
                if ($newintro != $intro->intro) {
                    if (!set_field('forumng', 'intro', addslashes($newintro), 'id', $intro->id)) {
                        throw new forum_exception("Failed to set intro for forum {$intro->id}: " . $db->ErrorMsg());
                    }
                }
            }
        }
        // 2. Post content
        $rs = get_recordset_sql("\nSELECT\n    fp.id, fp.message, fp.format\nFROM\n    {$CFG->prefix}forumng f\n    INNER JOIN {$CFG->prefix}forumng_discussions d ON d.forumid = f.id\n    INNER JOIN {$CFG->prefix}forumng_posts fp ON fp.discussionid = d.id\nWHERE\n    f.course={$restore->course_id}\n");
        if (!$rs) {
            throw new forum_exception("Failed to query for forum data: " . $db->ErrorMsg());
        }
        while ($rec = rs_fetch_next_record($rs)) {
            $newcontent = restore_decode_content_links_worker($rec->message, $restore);
            if ($newcontent != $rec->message) {
                if (!set_field('forumng_posts', 'message', addslashes($newcontent), 'id', $rec->id)) {
                    throw new forum_exception("Failed to update content {$ec->id}: " . $db->ErrorMsg());
                }
            }
        }
        rs_close($rs);
        // 3. Update search data (note this is not actually do with content
        //    links, but it has to be done here because we need a course-module
        //    id.
        if (forum::search_installed()) {
            forumng_ousearch_update_all(false, $restore->course_id);
        }
        return true;
    } catch (Exception $e) {
        forum_utils::handle_backup_exception($e, 'restore');
        return false;
    }
}
 /**
  * Displays a flagged item.
  * @param forum_post $post
  * @param bool $last
  * @return string HTML code for table row
  */
 public function display_flagged_list_item($post, $last)
 {
     global $CFG;
     // Classes for Moodle table styles
     static $rownum = 0;
     $classes = ' r' . $rownum;
     $rownum = 1 - $rownum;
     if ($last) {
         $classes .= ' lastrow';
     }
     $result = '<tr class="' . $classes . '">';
     // Post cell
     $result .= '<td class="cell c0">';
     // Get post URL
     $discussion = $post->get_discussion();
     $link = '<a href="discuss.php?' . $discussion->get_link_params(forum::PARAM_HTML) . '#p' . $post->get_id() . '">';
     // Get post summary
     $summary = self::get_post_summary($post->get_subject(), $post->get_message(), $post->get_format());
     $result .= $link . $summary . '</a>';
     $result .= '<small> ' . get_string('postby', 'forumng', $post->get_forum()->display_user_link($post->get_user())) . '</small>';
     // Show flag icon. (Note: I tried to use &nbsp; before this so the
     // icon never ends up on a line of its own, but it does not work.)
     $result .= ' <form class="forumng-flag" action="flagpost.php" method="post"><div>' . '<input type="hidden" name="p" value="' . $post->get_id() . '" />' . '<input type="hidden" name="back" value="view" />' . '<input type="hidden" name="flag" value="0" />' . '<input type="image" title="' . get_string('clearflag', 'forumng') . '" src="' . $CFG->modpixpath . '/forumng/flag.on.png" alt="' . get_string('flagon', 'forumng') . '" /></div></form></td>';
     // Discussion cell
     $result .= '<td class="cell c1"><a href="discuss.php?' . $discussion->get_link_params(forum::PARAM_HTML) . $discussion->get_id() . '">' . format_string($discussion->get_subject()) . '</a></td>';
     // Date cell
     $result .= '<td class="cell c2 lastcol">' . forum_utils::display_date($post->get_created()) . '</td></tr>';
     return $result;
 }
$cmid = required_param('id', PARAM_INT);
$cloneid = optional_param('clone', 0, PARAM_INT);
$file = required_param('file', PARAM_FILE);
$playspaceid = optional_param('attachmentplayspace', 0, PARAM_SEQUENCE);
$postid = optional_param('p', 0, PARAM_INT);
try {
    // Security check
    if ($postid) {
        $post = forum_post::get_from_id($postid, $cloneid);
        $post->require_view();
    } else {
        $forum = forum::get_from_cmid($cmid, $cloneid);
        $forum->require_view(forum::NO_GROUPS);
    }
    if (!$playspaceid) {
        $playspaceid = forum::create_attachment_playspace($postid ? $post : null);
    }
    // Delete the file (if not present, ignore)
    $files = forum::get_attachment_playspace_files($playspaceid, false);
    foreach ($files as $existing) {
        if (basename($existing) == $file) {
            forum_utils::unlink($existing);
        }
    }
    // Print out the playspace id in case they don't already have it
    header('Content-Type: text/plain');
    print $playspaceid;
} catch (forum_exception $e) {
    header('Content-Type: text/plain', true, 500);
    print $e->getMessage();
}
 private function add_attachment($path, $courseid = 0, $forumid = 0, $draftid = 0)
 {
     // Check source file exists
     if (!file_exists($path)) {
         throw new forum_exception("Missing file {$path}");
     }
     // Get folder
     if (isset($this)) {
         $folder = $this->get_attachment_folder();
     } else {
         $folder = self::get_attachment_folder($courseid, $forumid, $draftid);
     }
     if (!check_dir_exists($folder, true, true)) {
         throw new forum_exception("Failed to create attachment folder {$folder}");
     }
     // Check target path doesn't already exist. If it does, delete existing
     // file.
     $target = $folder . '/' . basename($path);
     if (file_exists($target)) {
         forum_utils::unlink($target);
     }
     // Move new file into place
     forum_utils::rename($path, $target);
 }
 /**
  * Given a parent folder, deletes all folders within it (and their
  * contents) if they are older than 24 hours.
  * @param float $start Start time
  * @param string $folder Folder path
  */
 private static function clear_old_folders($start, $folder)
 {
     // Threshold is 24 hours ago
     $threshold = time() - 24 * 3600;
     // Loop through all files in folder
     $killed = 0;
     $spared = 0;
     $handle = forum_utils::opendir($folder);
     while (($file = readdir($handle)) !== false) {
         if ($file == '.' || $file == '..') {
             continue;
         }
         // Check it's a folder
         $target = "{$folder}/{$file}";
         if (!is_dir($target)) {
             continue;
         }
         // Check time
         if (filemtime($target) < $threshold) {
             // Older than threshold - delete
             if (!remove_dir($target)) {
                 mtrace("\nError deleting folder: {$target}");
             }
             $killed++;
         } else {
             $spared++;
         }
     }
     closedir($handle);
     mtrace("({$killed} deleted, {$spared} left): " . round(microtime(true) - $start, 1));
 }
    $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));
    print skip_main_destination();
    // Show confirm option
    $confirmstring = get_string($delete ? 'confirmdeletediscussion' : 'confirmundeletediscussion', 'forumng');
    notice_yesno($confirmstring, 'delete.php', '../../discuss.php', array('d' => $discussion->get_id(), 'delete' => $delete, 'clone' => $cloneid), array('d' => $discussion->get_id(), 'clone' => $cloneid), 'post', 'get');
    // Display footer
    print_footer($course);
} catch (forum_exception $e) {
    forum_utils::handle_exception($e);
}
function forumng_backup_post($xb, $post)
{
    $xb->tag_start('POST');
    // Post data
    $xb->tag_full('ID', $post->id);
    $xb->tag_full_notnull('PARENTPOSTID', $post->parentpostid);
    forumng_backup_userid($xb, $post->userid);
    $xb->tag_full('CREATED', $post->created);
    $xb->tag_full('MODIFIED', $post->modified);
    $xb->tag_full('DELETED', $post->deleted);
    forumng_backup_userid($xb, $post->deleteuserid, 'DELETEUSERID');
    $xb->tag_full('MAILSTATE', $post->mailstate);
    $xb->tag_full('IMPORTANT', $post->important);
    $xb->tag_full('OLDVERSION', $post->oldversion);
    forumng_backup_userid($xb, $post->edituserid, 'EDITUSERID');
    $xb->tag_full_notnull('SUBJECT', $post->subject);
    $xb->tag_full('MESSAGE', $post->message);
    $xb->tag_full('FORMAT', $post->format);
    $xb->tag_full('ATTACHMENTS', $post->attachments);
    // Ratings
    $xb->tag_start('RATINGS');
    $rs = forum_utils::get_recordset('forumng_ratings', 'postid', $post->id);
    while ($rating = rs_fetch_next_record($rs)) {
        forumng_backup_rating($xb, $rating);
    }
    rs_close($rs);
    $xb->tag_end('RATINGS');
    // Flags
    $xb->tag_start('FLAGS');
    $rs = forum_utils::get_recordset('forumng_flags', 'postid', $post->id);
    while ($flag = rs_fetch_next_record($rs)) {
        forumng_backup_flag($xb, $flag);
    }
    rs_close($rs);
    $xb->tag_end('FLAGS');
    $xb->tag_end('POST');
}