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'); } }
/** * 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)); } }
/** * 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()); } }
/** * Creates a new ForumNG by copying data (including all messages etc) from * an old forum. The old forum will be hidden. * * Behaviour is undefined if the old forum wasn't eligible for conversion * (forum_utils::get_convertible_forums). * @param object $course Moodle course object * @param int $forumcmid Old forum to convert * @param bool $progress If true, print progress to output * @param bool $hide If true, newly-created forum is also hidden * @param bool $nodata If true, no user data (posts, subscriptions, etc) * is copied; you only get a forum with same configuration * @param bool $insection If true, remeber to create the new forumNG in the same section. * @throws forum_exception If any error occurs */ public static function create_from_old_forum($course, $forumcmid, $progress, $hide, $nodata, $insection = true) { global $CFG; // Start the clock and a database transaction $starttime = microtime(true); forum_utils::start_transaction(); // Note we do not use get_fast_modinfo because it doesn't contain the // complete $cm object. $cm = forum_utils::get_record('course_modules', 'id', $forumcmid); $forum = forum_utils::get_record('forum', 'id', $cm->instance); if ($progress) { print_heading(s($forum->name), '', 3); print '<ul><li>' . get_string('convert_process_init', 'forumng'); flush(); } // Hide forum forum_utils::update_record('course_modules', (object) array('id' => $cm->id, 'visible' => 0)); // Table for changed subscription constants $subscriptiontranslate = array(0 => 1, 1 => 3, 2 => 2, 3 => 0); // Get, convert, and create forum table data $forumng = (object) array('course' => $course->id, 'name' => addslashes($forum->name), 'type' => 'general', 'intro' => addslashes($forum->intro), 'ratingscale' => $forum->scale, 'ratingfrom' => $forum->assesstimestart, 'ratinguntil' => $forum->assesstimefinish, 'ratingthreshold' => 1, 'grading' => $forum->assessed, 'attachmentmaxbytes' => $forum->maxbytes, 'subscription' => $subscriptiontranslate[$forum->forcesubscribe], 'feedtype' => $forum->rsstype, 'feeditems' => $forum->rssarticles, 'maxpostsperiod' => $forum->blockperiod, 'maxpostsblock' => $forum->blockafter, 'postingfrom' => 0, 'postinguntil' => 0, 'typedata' => null); require_once $CFG->dirroot . '/mod/forumng/lib.php'; // Note: The idnumber is required. We cannot copy it because then there // would be a duplicate idnumber. Let's just leave blank, people will // have to configure this manually. $forumng->cmidnumber = ''; if (!($newforumid = forumng_add_instance($forumng))) { throw new forum_exception("Failed to add forumng instance"); } // Create and add course-modules entry $newcm = new stdClass(); $newcm->course = $course->id; $newcm->module = get_field('modules', 'id', 'name', 'forumng'); if (!$newcm->module) { throw new forum_exception("Cannot find forumng module id"); } $newcm->instance = $newforumid; $newcm->section = $cm->section; $newcm->added = time(); $newcm->score = $cm->score; $newcm->indent = $cm->indent; $newcm->visible = 0; // Forums are always hidden until finished $newcm->groupmode = $cm->groupmode; $newcm->groupingid = $cm->groupingid; $newcm->idnumber = $cm->idnumber; $newcm->groupmembersonly = $cm->groupmembersonly; // Include extra OU-specific data if (class_exists('ouflags')) { $newcm->showto = $cm->showto; $newcm->stealth = $cm->stealth; $newcm->parentcmid = $cm->parentcmid; $newcm->completion = $cm->completion; $newcm->completiongradeitemnumber = $cm->completiongradeitemnumber; $newcm->completionview = $cm->completionview; $newcm->availablefrom = $cm->availablefrom; $newcm->availableuntil = $cm->availableuntil; $newcm->showavailability = $cm->showavailability; $newcm->parentpagename = $cm->parentpagename; } // Add $newcm->id = forum_utils::insert_record('course_modules', $newcm); // Update section if ($insection) { $section = forum_utils::get_record('course_sections', 'id', $newcm->section); $updatesection = (object) array('id' => $section->id, 'sequence' => str_replace($cm->id, $cm->id . ',' . $newcm->id, $section->sequence)); if ($updatesection->sequence == $section->sequence) { throw new forum_exception("Unable to update sequence"); } forum_utils::update_record('course_sections', $updatesection); } // Construct forum object for new forum $newforum = self::get_from_id($forumng->id, forum::CLONE_DIRECT); if ($progress) { print ' ' . get_string('convert_process_state_done', 'forumng') . '</li>'; } if (!$nodata) { // Convert subscriptions switch ($newforum->get_effective_subscription_option()) { case self::SUBSCRIPTION_PERMITTED: if ($progress) { print '<li>' . get_string('convert_process_subscriptions_normal', 'forumng'); flush(); } // Standard subscription - just copy subscriptions $rs = forum_utils::get_recordset('forum_subscriptions', 'forum', $forum->id); while ($rec = rs_fetch_next_record($rs)) { forum_utils::insert_record('forumng_subscriptions', (object) array('forumid' => $forumng->id, 'userid' => $rec->userid, 'subscribed' => 1)); } rs_close($rs); if ($progress) { print ' ' . get_string('convert_process_state_done', 'forumng') . '</li>'; } break; case self::SUBSCRIPTION_INITIALLY_SUBSCRIBED: // Initial subscription is handled differently; the old forum // stores all the subscriptions in the database, while in this // forum we only store people who chose to unsubscribe if ($progress) { print '<li>' . get_string('convert_process_subscriptions_initial', 'forumng'); flush(); } // Get list of those subscribed on old forum $rs = forum_utils::get_recordset('forum_subscriptions', 'forum', $forum->id); $subscribedbefore = array(); while ($rec = rs_fetch_next_record($rs)) { $subscribedbefore[$rec->userid] = true; } rs_close(); // Get list of those subscribed on new forum $new = $newforum->get_subscribers(); // For anyone in the new list but not the old list, add an // unsubscribe foreach ($new as $user) { if (!array_key_exists($user->id, $subscribedbefore)) { forum_utils::insert_record('forumng_subscriptions', (object) array('forumid' => $forumng->id, 'userid' => $user->id, 'subscribed' => 0)); } } if ($progress) { print ' ' . get_string('convert_process_state_done', 'forumng') . '</li>'; } break; } // Convert discussions if ($progress) { print '<li>' . get_string('convert_process_discussions', 'forumng'); flush(); } $rsd = forum_utils::get_recordset('forum_discussions', 'forum', $forum->id); $count = 0; while ($recd = rs_fetch_next_record($rsd)) { // Convert discussion options $newd = (object) array('forumid' => $forumng->id, 'timestart' => $recd->timestart, 'timeend' => $recd->timeend, 'deleted' => 0, 'locked' => 0, 'sticky' => 0); if ($recd->groupid == -1 || !$newcm->groupmode) { $newd->groupid = null; } else { $newd->groupid = $recd->groupid; } // Save discussion $newd->id = forum_utils::insert_record('forumng_discussions', $newd); // Convert posts $lastposttime = -1; $discussionupdate = (object) array('id' => $newd->id); $postids = array(); // From old post id to new post id $parentposts = array(); // From new post id to old parent id $subjects = array(); // From new id to subject text (no slashes) $rsp = forum_utils::get_recordset('forum_posts', 'discussion', $recd->id); while ($recp = rs_fetch_next_record($rsp)) { // Convert post $newp = (object) array('discussionid' => $newd->id, 'userid' => $recp->userid, 'created' => $recp->created, 'modified' => $recp->modified, 'deleted' => 0, 'deleteuserid' => null, 'mailstate' => self::MAILSTATE_DIGESTED, 'oldversion' => 0, 'edituserid' => null, 'subject' => addslashes($recp->subject), 'message' => addslashes($recp->message), 'format' => $recp->format, 'important' => 0); // Are there any attachments? $attachments = array(); if (class_exists('ouflags')) { // OU has customisation for existing forum that supports // multiple attachments $attachmentrecords = forum_utils::get_records('forum_attachments', 'postid', $recp->id); foreach ($attachmentrecords as $reca) { $attachments[] = $reca->attachment; } } else { // Standard forum uses attachment field for filename if ($recp->attachment) { $attachments[] = $recp->attachment; } } $newp->attachments = count($attachments) ? 1 : 0; // Add record $newp->id = forum_utils::insert_record('forumng_posts', $newp); // Remember details for later parent update $postids[$recp->id] = $newp->id; if ($recp->parent) { $parentposts[$newp->id] = $recp->parent; } else { $discussionupdate->postid = $newp->id; } if ($newp->created > $lastposttime) { $discussionupdate->lastpostid = $newp->id; } $subjects[$newp->id] = $recp->subject; // Copy attachments $oldfolder = $CFG->dataroot . "/{$course->id}/{$CFG->moddata}/forum/{$forum->id}/{$recp->id}"; $newfolder = forum_post::get_any_attachment_folder($course->id, $forumng->id, $newd->id, $newp->id); $filesok = 0; $filesfailed = 0; foreach ($attachments as $attachment) { // Create folder if it isn't there $attachment = clean_filename($attachment); check_dir_exists($newfolder, true, true); // Copy file try { forum_utils::copy("{$oldfolder}/{$attachment}", "{$newfolder}/{$attachment}"); $filesok++; } catch (forum_exception $e) { if ($progress) { print "[<strong>Warning</strong>: file copy failed for post " . $recp->id . " => " . $newp->id . ", file " . s($attachment) . "]"; } $filesfailed++; } } // If all files failed, clean up if ($filesfailed && !$filesok) { rmdir($newfolder); $noattachments = (object) array('id' => $newp->id, 'attachments' => 0); forum_utils::update_record('forumng_posts', $noattachments); } // Convert ratings if ($forumng->ratingscale) { $rsr = get_recordset('forum_ratings', 'post', $recp->id); while ($recr = rs_fetch_next_record($rsr)) { forum_utils::insert_record('forumng_ratings', (object) array('postid' => $newp->id, 'userid' => $recr->userid, 'time' => $recr->time, 'rating' => $recr->rating)); } rs_close($rsr); } } rs_close($rsp); // Update parent numbers $newparentids = array(); foreach ($parentposts as $newid => $oldparentid) { if (!array_key_exists($oldparentid, $postids)) { throw new forum_exception("Unknown parent post {$oldparentid}"); } $newparentid = $postids[$oldparentid]; forum_utils::update_record('forumng_posts', (object) array('id' => $newid, 'parentpostid' => $newparentid)); $newparentids[$newid] = $newparentid; } // Update subjects $removesubjects = array(); // Array of ints to cancel subjects foreach ($newparentids as $newid => $newparentid) { $subject = $subjects[$newid]; $parentsubject = $subjects[$newparentid]; if ($subject && ($subject == get_string('re', 'forum') . ' ' . $parentsubject || $subject == $parentsubject)) { $removesubjects[] = $newid; } } if (count($removesubjects)) { $in = forum_utils::in_or_equals($removesubjects); forum_utils::execute_sql("UPDATE {$CFG->prefix}forumng_posts SET subject=NULL WHERE id {$in}"); } // Update first/last post numbers forum_utils::update_record('forumng_discussions', $discussionupdate); // Convert read data $rsr = forum_utils::get_recordset_sql("\nSELECT\n userid, MAX(lastread) AS lastread\nFROM\n {$CFG->prefix}forum_read\nWHERE\n discussionid = {$recd->id}\nGROUP BY\n userid"); while ($recr = rs_fetch_next_record($rsr)) { forum_utils::insert_record('forumng_read', (object) array('discussionid' => $newd->id, 'userid' => $recr->userid, 'time' => $recr->lastread)); } rs_close($rsr); // Display dot for each discussion if ($progress) { print '.'; $count++; if ($count % 10 == 0) { print $count; } flush(); } } rs_close($rsd); if ($progress) { print ' ' . get_string('convert_process_state_done', 'forumng') . '</li>'; } } // Show forum if (!$hide && $cm->visible) { if ($progress) { print '<li>' . get_string('convert_process_show', 'forumng'); flush(); } $updatecm = (object) array('id' => $newcm->id, 'visible' => 1); forum_utils::update_record('course_modules', $updatecm); if ($progress) { print ' ' . get_string('convert_process_state_done', 'forumng') . '</li>'; } } // Transfer role assignments $oldcontext = get_context_instance(CONTEXT_MODULE, $cm->id); $newcontext = get_context_instance(CONTEXT_MODULE, $newcm->id); $roles = get_records('role_assignments', 'contextid', $oldcontext->id); if ($roles) { if ($progress) { print '<li>' . get_string('convert_process_assignments', 'forumng'); flush(); } foreach ($roles as $role) { $newrole = $role; $newrole->contextid = $newcontext->id; $newrole->enrol = addslashes($newrole->enrol); forum_utils::insert_record('role_assignments', $newrole); } if ($progress) { print ' ' . get_string('convert_process_state_done', 'forumng') . '</li>'; } } // Transfer capabilities $capabilities = array('moodle/course:viewhiddenactivities' => 'moodle/course:viewhiddenactivities', 'moodle/site:accessallgroups' => 'moodle/site:accessallgroups', 'moodle/site:trustcontent' => 'moodle/site:trustcontent', 'moodle/site:viewfullnames' => 'moodle/site:viewfullnames', 'mod/forum:viewdiscussion' => 'mod/forumng:viewdiscussion', 'mod/forum:startdiscussion' => 'mod/forumng:startdiscussion', 'mod/forum:replypost' => 'mod/forumng:replypost', 'mod/forum:viewrating' => 'mod/forumng:viewrating', 'mod/forum:viewanyrating' => 'mod/forumng:viewanyrating', 'mod/forum:rate' => 'mod/forumng:rate', 'mod/forum:createattachment' => 'mod/forumng:createattachment', 'mod/forum:deleteanypost' => 'mod/forumng:deleteanypost', 'mod/forum:splitdiscussions' => 'mod/forumng:splitdiscussions', 'mod/forum:movediscussions' => 'mod/forumng:movediscussions', 'mod/forum:editanypost' => 'mod/forumng:editanypost', 'mod/forum:viewsubscribers' => 'mod/forumng:viewsubscribers', 'mod/forum:managesubscriptions' => 'mod/forumng:managesubscriptions', 'mod/forum:viewhiddentimedposts' => 'mod/forumng:viewallposts'); $caps = get_records('role_capabilities', 'contextid', $oldcontext->id); if ($caps) { if ($progress) { print '<li>' . get_string('convert_process_overrides', 'forumng'); flush(); } foreach ($caps as $cap) { foreach ($capabilities as $key => $capability) { if ($cap->capability != $key) { continue; } $newcap = $cap; $newcap->contextid = $newcontext->id; $newcap->capability = $capability; $newcap->capability = addslashes($newcap->capability); forum_utils::insert_record('role_capabilities', $newcap); } } if ($progress) { print ' ' . get_string('convert_process_state_done', 'forumng') . '</li>'; } } // Do course cache rebuild_course_cache($course->id, true); // Update search data if (self::search_installed()) { if ($progress) { print '<li>' . get_string('convert_process_search', 'forumng') . '</li>'; flush(); } self::search_update_all($progress, $course->id, $newcm->id); } // OU only: Transfer external dashboard details to new forum if (class_exists('ouflags')) { if ($progress) { print '<li>' . get_string('convert_process_dashboard', 'forumng'); flush(); } require_once $CFG->dirroot . '/local/externaldashboard/external_dashboard.php'; $a = new stdClass(); list($a->yay, $a->nay) = external_dashboard::transfer_favourites($forumcmid, $newcm->id); if ($progress) { print ' ' . get_string('convert_process_dashboard_done', 'forumng', $a) . '</li>'; } } if ($progress) { print '<li>' . get_string('convert_process_update_subscriptions', 'forumng'); flush(); } self::group_subscription_update(false, $newcm->id); if ($progress) { print ' ' . get_string('convert_process_state_done', 'forumng') . '</li>'; } forum_utils::finish_transaction(); if ($progress) { $a = (object) array('seconds' => round(microtime(true) - $starttime, 1), 'link' => '<a href="view.php?id=' . $newcm->id . '">' . get_string('convert_newforum', 'forumng') . '</a>'); print '</ul><p>' . get_string('convert_process_complete', 'forumng', $a) . '</p>'; } }
/** * Splits this post to become a new discussion * @param $newsubject * @param bool $log True to log action * @return int ID of new discussion */ function split($newsubject, $log = true) { global $CFG; $this->require_children(); // Begin a transaction forum_utils::start_transaction(); $olddiscussion = $this->get_discussion(); // Create new discussion $newest = null; $this->find_newest_child($newest); $newdiscussionid = $olddiscussion->clone_for_split($this->get_id(), $newest->get_id()); // Update all child posts $list = array(); $this->list_child_ids($list); unset($list[0]); // Don't include this post itself if (count($list) > 0) { $inorequals = forum_utils::in_or_equals($list); forum_utils::execute_sql("\nUPDATE\n {$CFG->prefix}forumng_posts\nSET\n discussionid = {$newdiscussionid}\nWHERE\n id {$inorequals}"); } // Update this post $changes = new stdClass(); $changes->id = $this->get_id(); $changes->subject = addslashes($newsubject); $changes->parentpostid = null; //When split the post, reset the important to 0 so that it is not highlighted. $changes->important = 0; // Note don't update modified time, or it makes this post unread, // which isn't very helpful $changes->discussionid = $newdiscussionid; forum_utils::update_record('forumng_posts', $changes); // Update read data if relevant if (forum::enabled_read_tracking() && $newest->get_modified() >= forum::get_read_tracking_deadline()) { $rs = forum_utils::get_recordset_sql("\nSELECT\n userid, time\nFROM\n {$CFG->prefix}forumng_read\nWHERE\n discussionid = " . $olddiscussion->get_id() . "\n AND time >= " . $this->get_created()); while ($rec = rs_fetch_next_record($rs)) { $rec->discussionid = $newdiscussionid; forum_utils::insert_record('forumng_read', $rec); } rs_close($rs); } $olddiscussion->possible_lastpost_change(); // Move attachments $olddiscussionfolder = $olddiscussion->get_attachment_folder(); $newdiscussionfolder = $olddiscussion->get_attachment_folder(0, 0, $newdiscussionid); if (is_dir($olddiscussionfolder)) { // Put this post back on the list $list[0] = $this->get_id(); // Loop through all posts; move attachments if present $madenewfolder = false; foreach ($list as $id) { $oldfolder = $olddiscussionfolder . '/' . $id; $newfolder = $newdiscussionfolder . '/' . $id; if (is_dir($oldfolder)) { if (!$madenewfolder) { check_dir_exists($newfolder, true, true); $madenewfolder = true; } forum_utils::rename($oldfolder, $newfolder); } } } if ($log) { $this->log('split post'); } forum_utils::finish_transaction(); $this->get_discussion()->uncache(); // If discussion-based completion is turned on, this may enable someone // to complete if ($this->get_forum()->get_completion_discussions()) { $this->update_completion(true); } return $newdiscussionid; }
function forumng_restore_mods($mod, $restore) { global $CFG; $status = true; //Get record from backup_ids $forumid = 0; if ($data = backup_getid($restore->backup_unique_code, $mod->modtype, $mod->id)) { try { if (!defined('RESTORE_SILENTLY')) { $name = $data->info['MOD']['#']['NAME']['0']['#']; echo "<li>" . get_string('modulename', 'forumng') . ' "' . htmlspecialchars($name) . '"</li>'; } // Boom. Now try restoring! $xml = $data->info['MOD']['#']; $userdata = restore_userdata_selected($restore, 'forumng', $mod->id); $forumng = new stdClass(); $forumng->course = $restore->course_id; $forumng->name = addslashes($xml['NAME'][0]['#']); // ForumNG-specific data if (isset($xml['TYPE'][0]['#'])) { $forumng->type = backup_todb($xml['TYPE'][0]['#']); } if (isset($xml['INTRO'][0]['#'])) { $forumng->intro = backup_todb($xml['INTRO'][0]['#']); } else { $forumng->intro = null; } $forumng->ratingscale = $xml['RATINGSCALE'][0]['#']; $forumng->ratingfrom = $xml['RATINGFROM'][0]['#']; $forumng->ratinguntil = $xml['RATINGUNTIL'][0]['#']; $forumng->ratingthreshold = $xml['RATINGTHRESHOLD'][0]['#']; $forumng->grading = $xml['GRADING'][0]['#']; $forumng->attachmentmaxbytes = $xml['ATTACHMENTMAXBYTES'][0]['#']; if (isset($xml['REPORTINGEMAIL'][0]['#'])) { $forumng->reportingemail = backup_todb($xml['REPORTINGEMAIL'][0]['#']); } $forumng->subscription = $xml['SUBSCRIPTION'][0]['#']; $forumng->feedtype = $xml['FEEDTYPE'][0]['#']; $forumng->feeditems = $xml['FEEDITEMS'][0]['#']; $forumng->maxpostsperiod = $xml['MAXPOSTSPERIOD'][0]['#']; $forumng->maxpostsblock = $xml['MAXPOSTSBLOCK'][0]['#']; $forumng->postingfrom = $xml['POSTINGFROM'][0]['#']; $forumng->postinguntil = $xml['POSTINGUNTIL'][0]['#']; if (isset($xml['TYPEDATA'][0]['#'])) { $forumng->typedata = backup_todb($xml['TYPEDATA'][0]['#']); } $forumng->magicnumber = $xml['MAGICNUMBER'][0]['#']; $forumng->completiondiscussions = $xml['COMPLETIONDISCUSSIONS'][0]['#']; $forumng->completionreplies = $xml['COMPLETIONREPLIES'][0]['#']; $forumng->completionposts = $xml['COMPLETIONPOSTS'][0]['#']; if (isset($xml['REMOVEAFTER'][0]['#'])) { $forumng->removeafter = $xml['REMOVEAFTER'][0]['#']; } if (isset($xml['REMOVETO'][0]['#'])) { $forumng->removeto = backup_todb($xml['REMOVETO'][0]['#']); } if (isset($xml['SHARED'][0]['#'])) { $forumng->shared = $xml['SHARED'][0]['#']; } // To protect the forum intro field from molestation if some idiot // sets it to a weird value... if (preg_match('~%%CMIDNUMBER:[^%]+%%$~', $forumng->intro)) { $forumng->intro .= '%%REMOVETHIS%%'; } if (isset($xml['ORIGINALCMIDNUMBER'][0]['#'])) { if ($forumng->intro === null) { $forumng->intro = ''; } // This is a bit of a hack, but we need to wait until everything // is restored, and it is a text value; so temporarily, add it // to the end of the intro field. $forumng->intro .= '%%CMIDNUMBER:' . backup_todb($xml['ORIGINALCMIDNUMBER'][0]['#']) . '%%'; } // Insert main record if (!($forumng->id = insert_record('forumng', $forumng))) { throw new forum_exception('Error creating forumng instance'); } $forumid = $forumng->id; backup_putid($restore->backup_unique_code, $mod->modtype, $mod->id, $forumng->id); if ($userdata) { if (isset($xml['DISCUSSIONS'][0]['#']['DISCUSSION'])) { foreach ($xml['DISCUSSIONS'][0]['#']['DISCUSSION'] as $xml_sub) { forumng_restore_discussion($restore, $xml_sub['#'], $forumng); } } if (isset($xml['SUBSCRIPTIONS'][0]['#']['SUBSCRIPTION'])) { foreach ($xml['SUBSCRIPTIONS'][0]['#']['SUBSCRIPTION'] as $xml_sub) { forumng_restore_subscription($restore, $xml_sub['#'], $forumng); } } // Attachments xml_backup::restore_module_files($restore->backup_unique_code, $restore->course_id, 'forumng', $mod->id); $basepath = $CFG->dataroot . '/' . $restore->course_id . '/moddata/forumng'; rename($basepath . '/' . $mod->id, $basepath . '/' . $forumng->id); } } catch (Exception $e) { // Clean out any partially-created data try { forum_utils::execute_sql("\nDELETE FROM {$CFG->prefix}forumng_ratings\nWHERE postid IN (\nSELECT fp.id\nFROM\n {$CFG->prefix}forumng_discussions fd\n INNER JOIN {$CFG->prefix}forumng_posts fp ON fp.discussionid = fd.id\nWHERE\n fd.forumid = {$forumid}\n)"); $discussionquery = "\nWHERE discussionid IN (\nSELECT id FROM {$CFG->prefix}forumng_discussions WHERE forumid={$forumid})"; forum_utils::execute_sql("DELETE FROM {$CFG->prefix}forumng_posts {$discussionquery}"); forum_utils::execute_sql("DELETE FROM {$CFG->prefix}forumng_read {$discussionquery}"); forum_utils::delete_records('forumng_subscriptions', 'forumid', $forumid); forum_utils::delete_records('forumng_discussions', 'forumid', $forumid); forum_utils::delete_records('forumng', 'id', $forumid); } catch (Exception $e) { debugging('Error occurred when trying to clean partial data'); } forum_utils::handle_backup_exception($e, 'restore'); $status = false; } } return $status; }