See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * The main interface for recycle bin methods. 19 * 20 * @package tool_recyclebin 21 * @copyright 2015 University of Kent 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace tool_recyclebin; 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 define('TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA', 'recyclebin_course'); 30 31 /** 32 * Represents a course's recyclebin. 33 * 34 * @package tool_recyclebin 35 * @copyright 2015 University of Kent 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class course_bin extends base_bin { 39 40 /** 41 * @var int The course id. 42 */ 43 protected $_courseid; 44 45 /** 46 * Constructor. 47 * 48 * @param int $courseid Course ID. 49 */ 50 public function __construct($courseid) { 51 $this->_courseid = $courseid; 52 } 53 54 /** 55 * Is this recyclebin enabled? 56 * 57 * @return bool true if enabled, false if not. 58 */ 59 public static function is_enabled() { 60 return get_config('tool_recyclebin', 'coursebinenable'); 61 } 62 63 /** 64 * Returns an item from the recycle bin. 65 * 66 * @param int $itemid Item ID to retrieve. 67 * @return \stdClass the item. 68 */ 69 public function get_item($itemid) { 70 global $DB; 71 72 return $DB->get_record('tool_recyclebin_course', array( 73 'id' => $itemid 74 ), '*', MUST_EXIST); 75 } 76 77 /** 78 * Returns a list of items in the recycle bin for this course. 79 * 80 * @return array the list of items. 81 */ 82 public function get_items() { 83 global $DB; 84 85 return $DB->get_records('tool_recyclebin_course', array( 86 'courseid' => $this->_courseid 87 )); 88 } 89 90 /** 91 * Store a course module in the recycle bin. 92 * 93 * @param \stdClass $cm Course module 94 * @throws \moodle_exception 95 */ 96 public function store_item($cm) { 97 global $CFG, $DB; 98 99 require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); 100 101 // Get more information. 102 $modinfo = get_fast_modinfo($cm->course); 103 104 if (!isset($modinfo->cms[$cm->id])) { 105 return; // Can't continue without the module information. 106 } 107 108 $cminfo = $modinfo->cms[$cm->id]; 109 110 // Check backup/restore support. 111 if (!plugin_supports('mod', $cminfo->modname , FEATURE_BACKUP_MOODLE2)) { 112 return; 113 } 114 115 // As far as recycle bin is using MODE_AUTOMATED, it observes the backup_auto_storage 116 // settings (storing backups @ real location and potentially not including files). 117 // For recycle bin we want to ensure that backup files are always stored in Moodle file 118 // area and always contain the users' files. In order to achieve that, we hack the 119 // setting here via $CFG->forced_plugin_settings, so it won't interfere other operations. 120 // See MDL-65218 and MDL-35773 for more information. 121 // This hack will be removed once recycle bin switches to use its own backup mode, with 122 // own preferences and 100% separate from MOODLE_AUTOMATED. 123 // TODO: Remove this as part of MDL-65228. 124 $CFG->forced_plugin_settings['backup'] = ['backup_auto_storage' => 0, 'backup_auto_files' => 1]; 125 126 // Backup the activity. 127 $user = get_admin(); 128 $controller = new \backup_controller( 129 \backup::TYPE_1ACTIVITY, 130 $cm->id, 131 \backup::FORMAT_MOODLE, 132 \backup::INTERACTIVE_NO, 133 \backup::MODE_AUTOMATED, 134 $user->id 135 ); 136 137 // When "backup_auto_activities" setting is disabled, activities can't be restored from recycle bin. 138 $plan = $controller->get_plan(); 139 $activitiessettings = $plan->get_setting('activities'); 140 $settingsvalue = $activitiessettings->get_value(); 141 if (empty($settingsvalue)) { 142 $controller->destroy(); 143 return; 144 } 145 146 $controller->execute_plan(); 147 148 // We don't need the forced setting anymore, hence unsetting it. 149 // TODO: Remove this as part of MDL-65228. 150 unset($CFG->forced_plugin_settings['backup']); 151 152 // Grab the result. 153 $result = $controller->get_results(); 154 if (!isset($result['backup_destination'])) { 155 throw new \moodle_exception('Failed to backup activity prior to deletion.'); 156 } 157 158 // Have finished with the controller, let's destroy it, freeing mem and resources. 159 $controller->destroy(); 160 161 // Grab the filename. 162 $file = $result['backup_destination']; 163 if (!$file->get_contenthash()) { 164 throw new \moodle_exception('Failed to backup activity prior to deletion (invalid file).'); 165 } 166 167 // Record the activity, get an ID. 168 $activity = new \stdClass(); 169 $activity->courseid = $cm->course; 170 $activity->section = $cm->section; 171 $activity->module = $cm->module; 172 $activity->name = $cminfo->name; 173 $activity->timecreated = time(); 174 $binid = $DB->insert_record('tool_recyclebin_course', $activity); 175 176 // Create the location we want to copy this file to. 177 $filerecord = array( 178 'contextid' => \context_course::instance($this->_courseid)->id, 179 'component' => 'tool_recyclebin', 180 'filearea' => TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA, 181 'itemid' => $binid, 182 'timemodified' => time() 183 ); 184 185 // Move the file to our own special little place. 186 $fs = get_file_storage(); 187 if (!$fs->create_file_from_storedfile($filerecord, $file)) { 188 // Failed, cleanup first. 189 $DB->delete_records('tool_recyclebin_course', array( 190 'id' => $binid 191 )); 192 193 throw new \moodle_exception("Failed to copy backup file to recyclebin."); 194 } 195 196 // Delete the old file. 197 $file->delete(); 198 199 // Fire event. 200 $event = \tool_recyclebin\event\course_bin_item_created::create(array( 201 'objectid' => $binid, 202 'context' => \context_course::instance($cm->course) 203 )); 204 $event->trigger(); 205 } 206 207 /** 208 * Restore an item from the recycle bin. 209 * 210 * @param \stdClass $item The item database record 211 * @throws \moodle_exception 212 */ 213 public function restore_item($item) { 214 global $CFG, $OUTPUT, $PAGE; 215 216 require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php'); 217 218 $user = get_admin(); 219 220 // Grab the course context. 221 $context = \context_course::instance($this->_courseid); 222 223 // Get the files.. 224 $fs = get_file_storage(); 225 $files = $fs->get_area_files($context->id, 'tool_recyclebin', TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA, $item->id, 226 'itemid, filepath, filename', false); 227 228 if (empty($files)) { 229 throw new \moodle_exception('Invalid recycle bin item!'); 230 } 231 232 if (count($files) > 1) { 233 throw new \moodle_exception('Too many files found!'); 234 } 235 236 // Get the backup file. 237 $file = reset($files); 238 239 // Get a backup temp directory name and create it. 240 $tempdir = \restore_controller::get_tempdir_name($context->id, $user->id); 241 $fulltempdir = make_backup_temp_directory($tempdir); 242 243 // Extract the backup to tempdir. 244 $fb = get_file_packer('application/vnd.moodle.backup'); 245 $fb->extract_to_pathname($file, $fulltempdir); 246 247 // As far as recycle bin is using MODE_AUTOMATED, it observes the General restore settings. 248 // For recycle bin we want to ensure that backup files are always restore the users and groups information. 249 // In order to achieve that, we hack the setting here via $CFG->forced_plugin_settings, 250 // so it won't interfere other operations. 251 // See MDL-65218 and MDL-35773 for more information. 252 // This hack will be removed once recycle bin switches to use its own backup mode, with 253 // own preferences and 100% separate from MOODLE_AUTOMATED. 254 // TODO: Remove this as part of MDL-65228. 255 $CFG->forced_plugin_settings['restore'] = ['restore_general_users' => 1, 'restore_general_groups' => 1]; 256 257 // Define the import. 258 $controller = new \restore_controller( 259 $tempdir, 260 $this->_courseid, 261 \backup::INTERACTIVE_NO, 262 \backup::MODE_AUTOMATED, 263 $user->id, 264 \backup::TARGET_EXISTING_ADDING 265 ); 266 267 // Prechecks. 268 if (!$controller->execute_precheck()) { 269 $results = $controller->get_precheck_results(); 270 271 // If errors are found then delete the file we created. 272 if (!empty($results['errors'])) { 273 fulldelete($fulltempdir); 274 275 echo $OUTPUT->header(); 276 $backuprenderer = $PAGE->get_renderer('core', 'backup'); 277 echo $backuprenderer->precheck_notices($results); 278 echo $OUTPUT->continue_button(new \moodle_url('/course/view.php', array('id' => $this->_courseid))); 279 echo $OUTPUT->footer(); 280 exit(); 281 } 282 } 283 284 // Run the import. 285 $controller->execute_plan(); 286 287 // We don't need the forced setting anymore, hence unsetting it. 288 // TODO: Remove this as part of MDL-65228. 289 unset($CFG->forced_plugin_settings['restore']); 290 291 // Have finished with the controller, let's destroy it, freeing mem and resources. 292 $controller->destroy(); 293 294 // Fire event. 295 $event = \tool_recyclebin\event\course_bin_item_restored::create(array( 296 'objectid' => $item->id, 297 'context' => $context 298 )); 299 $event->add_record_snapshot('tool_recyclebin_course', $item); 300 $event->trigger(); 301 302 // Cleanup. 303 fulldelete($fulltempdir); 304 $this->delete_item($item); 305 } 306 307 /** 308 * Delete an item from the recycle bin. 309 * 310 * @param \stdClass $item The item database record 311 */ 312 public function delete_item($item) { 313 global $DB; 314 315 // Grab the course context. 316 $context = \context_course::instance($this->_courseid, IGNORE_MISSING); 317 318 if (!empty($context)) { 319 // Delete the files. 320 $fs = get_file_storage(); 321 $fs->delete_area_files($context->id, 'tool_recyclebin', TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA, $item->id); 322 } else { 323 // Course context has been deleted. Find records using $item->id as this is unique for course bin recyclebin. 324 $files = $DB->get_recordset('files', [ 325 'component' => 'tool_recyclebin', 326 'filearea' => TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA, 327 'itemid' => $item->id, 328 ]); 329 $fs = get_file_storage(); 330 foreach ($files as $filer) { 331 $file = $fs->get_file_instance($filer); 332 $file->delete(); 333 } 334 $files->close(); 335 } 336 337 // Delete the record. 338 $DB->delete_records('tool_recyclebin_course', array( 339 'id' => $item->id 340 )); 341 342 // The course might have been deleted, check we have a context. 343 $context = \context_course::instance($item->courseid, \IGNORE_MISSING); 344 if (!$context) { 345 return; 346 } 347 348 // Fire event. 349 $event = \tool_recyclebin\event\course_bin_item_deleted::create(array( 350 'objectid' => $item->id, 351 'context' => $context 352 )); 353 $event->add_record_snapshot('tool_recyclebin_course', $item); 354 $event->trigger(); 355 } 356 357 /** 358 * Can we view items in this recycle bin? 359 * 360 * @return bool returns true if they can view, false if not 361 */ 362 public function can_view() { 363 $context = \context_course::instance($this->_courseid); 364 return has_capability('tool/recyclebin:viewitems', $context); 365 } 366 367 /** 368 * Can we restore items in this recycle bin? 369 * 370 * @return bool returns true if they can restore, false if not 371 */ 372 public function can_restore() { 373 $context = \context_course::instance($this->_courseid); 374 return has_capability('tool/recyclebin:restoreitems', $context); 375 } 376 377 /** 378 * Can we delete this? 379 * 380 * @return bool returns true if they can delete, false if not 381 */ 382 public function can_delete() { 383 $context = \context_course::instance($this->_courseid); 384 return has_capability('tool/recyclebin:deleteitems', $context); 385 } 386 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body