if (!$canmanage) {
         print_error('unsubscribe_nopermission', 'forumng');
     }
     $subscribers = $forum->get_subscribers($groupid);
     forum_utils::start_transaction();
     foreach (array_keys($_POST) as $key) {
         $matches = array();
         if (preg_match('~^user([0-9]+)$~', $key, $matches)) {
             // Use the subscribe list to check this user is on it. That
             // means they can't unsubscribe users in different groups.
             if (array_key_exists($matches[1], $subscribers)) {
                 $forum->unsubscribe($matches[1]);
             }
         }
     }
     forum_utils::finish_transaction();
     redirect('subscribers.php?' . $forum->get_link_params(forum::PARAM_PLAIN));
 }
 // Display header
 $navigation = array();
 $navigation[] = array('name' => get_string('subscribers', 'forumng'), 'type' => 'forumng');
 print_header_simple(format_string($forum->get_name()), '', build_navigation($navigation, $cm), '', '', true, '', navmenu($course, $cm));
 $forum->print_js();
 // Display group selector if required
 groups_print_activity_menu($cm, $CFG->wwwroot . '/mod/forumng/subscribers.php?' . $forum->get_link_params(forum::PARAM_PLAIN));
 // Get all subscribers
 $subscribers = $forum->get_subscribers();
 $individualgroup = $groupid != forum::ALL_GROUPS && $groupid != forum::NO_GROUPS;
 //Remove the subscribers to other groups and discussions which don't belong to this group
 if ($individualgroup) {
     foreach ($subscribers as $key => $user) {
 /**
  * Deletes an existing draft message.
  */
 function delete()
 {
     forum_utils::start_transaction();
     // Delete record
     forum_utils::delete_records('forumng_drafts', 'id', $this->draftfields->id);
     // Delete attachments
     $folder = $this->get_attachment_folder();
     if (is_dir($folder)) {
         $handle = forum_utils::opendir($folder);
         while (false !== ($name = readdir($handle))) {
             if ($name != '.' && $name != '..') {
                 forum_utils::unlink("{$folder}/{$name}");
             }
         }
         closedir($handle);
         forum_utils::rmdir($folder);
     }
     forum_utils::finish_transaction();
 }
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>";
}
 static function delete_old_posts()
 {
     global $CFG;
     // Check if deletion is turned off
     if (empty($CFG->forumng_permanentdeletion)) {
         return;
     }
     mtrace('Beginning forum deleted/edit message cleanup...');
     // Work out how long ago things have to have been 'deleted' before we
     // permanently delete them
     $deletebefore = time() - $CFG->forumng_permanentdeletion;
     // Handle all posts which were deleted (that long ago) or which are in
     // discussions which were deleted (that long ago)
     $mainquery = "\nFROM\n    {$CFG->prefix}forumng_posts fp\n    INNER JOIN {$CFG->prefix}forumng_discussions fd ON fd.id = fp.discussionid\n    INNER JOIN {$CFG->prefix}forumng f ON fd.forumid = f.id\nWHERE\n    (fp.deleted<>0 AND fp.deleted<{$deletebefore})\n    OR (fp.oldversion<>0 AND fp.modified<{$deletebefore})\n    OR (fd.deleted<>0 AND fd.deleted<{$deletebefore})";
     $idquery = "SELECT fp.id {$mainquery} ";
     $before = microtime(true);
     mtrace('Message search: ', '');
     $count = count_records_sql("SELECT COUNT(1) {$mainquery}");
     mtrace(round(microtime(true) - $before, 1) . 's');
     if ($count == 0) {
         mtrace("No old deleted / edited messages to clean up.");
     } else {
         mtrace("Permanently deleting {$count} old deleted / edited messages.");
     }
     if ($count) {
         $before = microtime(true);
         mtrace('Database post deletion: ', '');
         forum_utils::start_transaction();
         // Delete all ratings
         forum_utils::execute_sql("DELETE FROM {$CFG->prefix}forumng_ratings WHERE postid IN ({$idquery})");
         // Find all attachments
         $attachmentrecords = forum_utils::get_records_sql("\nSELECT\n    fp.id AS postid, fd.id AS discussionid, f.id AS forumid, f.course AS courseid\n{$mainquery}\n    AND fp.attachments<>0");
         // Delete all posts
         forum_utils::update_with_subquery_grrr_mysql("DELETE FROM {$CFG->prefix}forumng_posts WHERE id %'IN'%", $idquery);
         // Now delete all discussions
         forum_utils::execute_sql("DELETE FROM {$CFG->prefix}forumng_discussions " . "WHERE deleted<>0 AND deleted<{$deletebefore}");
         mtrace(round(microtime(true) - $before, 1) . 's');
         $before = microtime(true);
         mtrace('Filesystem attachment deletion: ', '');
         // OK, now delete attachments (this is done last in case the db update
         // failed and gets rolled back)
         foreach ($attachmentrecords as $attachmentrecord) {
             $folder = forum_post::get_any_attachment_folder($attachmentrecord->courseid, $attachmentrecord->forumid, $attachmentrecord->discussionid, $attachmentrecord->postid);
             // Delete post folder
             if (!remove_dir($folder)) {
                 mtrace("\nError deleting post folder: {$folder}");
                 // But don't stop because we can't undo earlier changes
             }
         }
         // Get list of all discussions that might need deleting
         $discussions = array();
         foreach ($attachmentrecords as $attachmentrecord) {
             // This will ensure we have only one entry per discussion
             $discussions[$attachmentrecord->discussionid] = $attachmentrecord;
         }
         // Delete discussion folder only if empty (there might be other
         // not-yet-deleted posts)
         foreach ($discussions as $attachmentrecord) {
             $folder = forum_discussion::get_attachment_folder($attachmentrecord->courseid, $attachmentrecord->forumid, $attachmentrecord->discussionid);
             $handle = @opendir($folder);
             if (!$handle) {
                 mtrace("\nError opening discussion folder: {$folder}");
                 continue;
             }
             $gotfiles = false;
             while (($file = readdir($handle)) !== false) {
                 if ($file != '.' && $file != '..') {
                     $gotfiles = true;
                     break;
                 }
             }
             closedir($handle);
             if (!$gotfiles) {
                 if (!rmdir($folder)) {
                     mtrace("\nError deleting discussion folder: {$folder}");
                 }
             }
         }
         forum_utils::finish_transaction();
         mtrace(round(microtime(true) - $before, 1) . 's');
     }
 }
 /**
  * Unsubscribe a user from this discussion.
  * @param $userid User ID (default current)
  * @param $log True to log this
  */
 public function unsubscribe($userid = 0, $log = true)
 {
     global $CFG;
     $userid = forum_utils::get_real_userid($userid);
     // For shared forums, we subscribe to a specific clone
     if ($this->get_forum()->is_shared()) {
         $clonecmid = $this->get_forum()->get_course_module_id();
         $clonevalue = '=' . $clonecmid;
     } else {
         $clonecmid = null;
         $clonevalue = 'IS NULL';
     }
     forum_utils::start_transaction();
     //Clear any previous subscriptions to this discussion from the same user if any
     forum_utils::execute_sql("DELETE FROM {$CFG->prefix}forumng_subscriptions " . "WHERE userid=" . $userid . " AND discussionid=" . $this->discussionfields->id . ' AND clonecmid ' . $clonevalue);
     forum_utils::finish_transaction();
     if ($log) {
         $this->log('unsubscribe', $userid . ' discussion ' . $this->get_id());
     }
 }
 /**
  * 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();
 }
 /**
  * Rates this post or updates an existing rating.
  * @param $rating Rating (value depends on scale used) or NO_RATING
  * @param $userid User ID or 0 for current user
  */
 function rate($rating, $userid = 0)
 {
     if (!$userid) {
         global $USER;
         $userid = $USER->id;
     }
     forum_utils::start_transaction();
     // Delete any existing rating
     forum_utils::delete_records('forumng_ratings', 'postid', $this->postfields->id, 'userid', $userid);
     // Add new rating
     if ($rating != self::NO_RATING) {
         $ratingobj = new StdClass();
         $ratingobj->userid = $userid;
         $ratingobj->postid = $this->postfields->id;
         $ratingobj->time = time();
         $ratingobj->rating = $rating;
         forum_utils::insert_record('forumng_ratings', $ratingobj);
     }
     // Tell grade to update
     if ($this->get_forum()->get_grading()) {
         $this->get_forum()->update_grades($this->get_user()->id);
     }
     forum_utils::finish_transaction();
     $this->get_discussion()->uncache();
 }