/**
  * 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();
 }
 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');
     }
 }
 /**
  * Gets the attachment folder for any post.
  * @param int $courseid Course
  * @param int $forumid Forum
  * @param int $discussionid Discussion
  * @param int $postid Post
  */
 static function get_any_attachment_folder($courseid, $forumid, $discussionid, $postid)
 {
     return forum_discussion::get_attachment_folder($courseid, $forumid, $discussionid) . '/' . $postid;
 }