Rev 1 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>./*** The main interface for recycle bin methods.** @package tool_recyclebin* @copyright 2015 University of Kent* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/namespace tool_recyclebin;defined('MOODLE_INTERNAL') || die();define('TOOL_RECYCLEBIN_COURSECAT_BIN_FILEAREA', 'recyclebin_coursecat');/*** Represents a category's recyclebin.** @package tool_recyclebin* @copyright 2015 University of Kent* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/class category_bin extends base_bin {/*** @var int The category id.*/protected $_categoryid;/*** Constructor.** @param int $categoryid The category id.*/public function __construct($categoryid) {$this->_categoryid = $categoryid;}/*** Is this recyclebin enabled?** @return bool true if enabled, false if not.*/public static function is_enabled() {return get_config('tool_recyclebin', 'categorybinenable');}/*** Returns an item from the recycle bin.** @param int $itemid Item ID to retrieve.* @return \stdClass the item.*/public function get_item($itemid) {global $DB;$item = $DB->get_record('tool_recyclebin_category', array('id' => $itemid), '*', MUST_EXIST);$item->name = get_course_display_name_for_list($item);return $item;}/*** Returns a list of items in the recycle bin for this course.** @return array the list of items.*/public function get_items() {global $DB;$items = $DB->get_records('tool_recyclebin_category', array('categoryid' => $this->_categoryid));foreach ($items as $item) {$item->name = get_course_display_name_for_list($item);}return $items;}/*** Store a course in the recycle bin.** @param \stdClass $course Course* @throws \moodle_exception*/public function store_item($course) {global $CFG, $DB;require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');// As far as recycle bin is using MODE_AUTOMATED, it observes the backup_auto_storage// settings (storing backups @ real location and potentially not including files).// For recycle bin we want to ensure that backup files are always stored in Moodle file// area and always contain the users' files. In order to achieve that, we hack the// setting here via $CFG->forced_plugin_settings, so it won't interfere other operations.// See MDL-65218 and MDL-35773 for more information.// This hack will be removed once recycle bin switches to use its own backup mode, with// own preferences and 100% separate from MOODLE_AUTOMATED.// TODO: Remove this as part of MDL-65228.$forcedbackupsettings = $CFG->forced_plugin_settings['backup'] ?? null;$CFG->forced_plugin_settings['backup']['backup_auto_storage'] = 0;$CFG->forced_plugin_settings['backup']['backup_auto_files'] = 1;// Backup the course.$user = get_admin();$controller = new \backup_controller(\backup::TYPE_1COURSE,$course->id,\backup::FORMAT_MOODLE,\backup::INTERACTIVE_NO,\backup::MODE_AUTOMATED,$user->id);$controller->execute_plan();// We don't need the forced setting anymore, hence restore previous settings.// TODO: Remove this as part of MDL-65228.$CFG->forced_plugin_settings['backup'] = $forcedbackupsettings;// Grab the result.$result = $controller->get_results();if (!isset($result['backup_destination'])) {throw new \moodle_exception('Failed to backup activity prior to deletion.');}// Have finished with the controller, let's destroy it, freeing mem and resources.$controller->destroy();// Grab the filename.$file = $result['backup_destination'];if (!$file->get_contenthash()) {throw new \moodle_exception('Failed to backup activity prior to deletion (invalid file).');}// Record the activity, get an ID.$item = new \stdClass();$item->categoryid = $course->category;$item->shortname = $course->shortname;$item->fullname = $course->fullname;$item->timecreated = time();$binid = $DB->insert_record('tool_recyclebin_category', $item);// Create the location we want to copy this file to.$filerecord = array('contextid' => \context_coursecat::instance($course->category)->id,'component' => 'tool_recyclebin','filearea' => TOOL_RECYCLEBIN_COURSECAT_BIN_FILEAREA,'itemid' => $binid,'timemodified' => time());// Move the file to our own special little place.$fs = get_file_storage();if (!$fs->create_file_from_storedfile($filerecord, $file)) {// Failed, cleanup first.$DB->delete_records('tool_recyclebin_category', array('id' => $binid));throw new \moodle_exception("Failed to copy backup file to recyclebin.");}// Delete the old file.$file->delete();// Fire event.$event = \tool_recyclebin\event\category_bin_item_created::create(array('objectid' => $binid,'context' => \context_coursecat::instance($course->category)));$event->trigger();}/*** Restore an item from the recycle bin.** @param \stdClass $item The item database record* @throws \moodle_exception*/public function restore_item($item) {global $CFG, $OUTPUT, $PAGE;require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');require_once($CFG->dirroot . '/course/lib.php');$user = get_admin();// Grab the course category context.$context = \context_coursecat::instance($this->_categoryid);// Get the backup file.$fs = get_file_storage();$files = $fs->get_area_files($context->id, 'tool_recyclebin', TOOL_RECYCLEBIN_COURSECAT_BIN_FILEAREA, $item->id,'itemid, filepath, filename', false);if (empty($files)) {throw new \moodle_exception('Invalid recycle bin item!');}if (count($files) > 1) {throw new \moodle_exception('Too many files found!');}// Get the backup file.$file = reset($files);// Get a backup temp directory name and create it.$tempdir = \restore_controller::get_tempdir_name($context->id, $user->id);$fulltempdir = make_backup_temp_directory($tempdir);// Extract the backup to tmpdir.$fb = get_file_packer('application/vnd.moodle.backup');$fb->extract_to_pathname($file, $fulltempdir);// Build a course.$course = new \stdClass();$course->category = $this->_categoryid;$course->shortname = $item->shortname;$course->fullname = $item->fullname;$course->summary = '';// Create a new course.$course = create_course($course);if (!$course) {throw new \moodle_exception("Could not create course to restore into.");}// As far as recycle bin is using MODE_AUTOMATED, it observes the General restore settings.// For recycle bin we want to ensure that backup files are always restore the users and groups information.// In order to achieve that, we hack the setting here via $CFG->forced_plugin_settings,// so it won't interfere other operations.// See MDL-65218 and MDL-35773 for more information.// This hack will be removed once recycle bin switches to use its own backup mode, with// own preferences and 100% separate from MOODLE_AUTOMATED.// TODO: Remove this as part of MDL-65228.$forcedrestoresettings = $CFG->forced_plugin_settings['restore'] ?? null;$CFG->forced_plugin_settings['restore']['restore_general_users'] = 1;$CFG->forced_plugin_settings['restore']['restore_general_groups'] = 1;// Define the import.$controller = new \restore_controller($tempdir,$course->id,\backup::INTERACTIVE_NO,\backup::MODE_AUTOMATED,$user->id,\backup::TARGET_NEW_COURSE);// Prechecks.if (!$controller->execute_precheck()) {$results = $controller->get_precheck_results();// Check if errors have been found.if (!empty($results['errors'])) {// Delete the temporary file we created.fulldelete($fulltempdir);// Delete the course we created.delete_course($course, false);echo $OUTPUT->header();$backuprenderer = $PAGE->get_renderer('core', 'backup');echo $backuprenderer->precheck_notices($results);echo $OUTPUT->continue_button(new \moodle_url('/course/index.php', array('categoryid' => $this->_categoryid)));echo $OUTPUT->footer();exit();}}// Run the import.$controller->execute_plan();// We don't need the forced setting anymore, hence restore previous settings.// TODO: Remove this as part of MDL-65228.$CFG->forced_plugin_settings['restore'] = $forcedrestoresettings;// Have finished with the controller, let's destroy it, freeing mem and resources.$controller->destroy();// Fire event.$event = \tool_recyclebin\event\category_bin_item_restored::create(array('objectid' => $item->id,'context' => $context));$event->add_record_snapshot('tool_recyclebin_category', $item);$event->trigger();// Cleanup.fulldelete($fulltempdir);$this->delete_item($item);}/*** Delete an item from the recycle bin.** @param \stdClass $item The item database record* @throws \coding_exception*/public function delete_item($item) {global $DB;// Grab the course category context.$context = \context_coursecat::instance($this->_categoryid, IGNORE_MISSING);if (!empty($context)) {// Delete the files.$fs = get_file_storage();$fs->delete_area_files($context->id, 'tool_recyclebin', TOOL_RECYCLEBIN_COURSECAT_BIN_FILEAREA, $item->id);} else {// Course category has been deleted. Find records using $item->id as this is unique for coursecat recylebin.$files = $DB->get_recordset('files', ['component' => 'tool_recyclebin','filearea' => TOOL_RECYCLEBIN_COURSECAT_BIN_FILEAREA,'itemid' => $item->id,]);$fs = get_file_storage();foreach ($files as $filer) {$file = $fs->get_file_instance($filer);$file->delete();}$files->close();}// Delete the record.$DB->delete_records('tool_recyclebin_category', array('id' => $item->id));// The coursecat might have been deleted, check we have a context before triggering event.if (!$context) {return;}// Fire event.$event = \tool_recyclebin\event\category_bin_item_deleted::create(array('objectid' => $item->id,'context' => \context_coursecat::instance($item->categoryid)));$event->add_record_snapshot('tool_recyclebin_category', $item);$event->trigger();}/*** Can we view items in this recycle bin?** @return bool returns true if they can view, false if not*/public function can_view() {$context = \context_coursecat::instance($this->_categoryid);return has_capability('tool/recyclebin:viewitems', $context);}/*** Can we restore items in this recycle bin?** @return bool returns true if they can restore, false if not*/public function can_restore() {$context = \context_coursecat::instance($this->_categoryid);return has_capability('tool/recyclebin:restoreitems', $context);}/*** Can we delete items in this recycle bin?** @return bool returns true if they can delete, false if not*/public function can_delete() {$context = \context_coursecat::instance($this->_categoryid);return has_capability('tool/recyclebin:deleteitems', $context);}}