a05a7cfd845a0ffccae7e6c73e82d7fa739d3ce2
[moodle.git] / admin / tool / recyclebin / classes / course_bin.php
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/>.
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  */
25 namespace tool_recyclebin;
27 defined('MOODLE_INTERNAL') || die();
29 define('TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA', 'recyclebin_course');
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 {
40     /**
41      * @var int The course id.
42      */
43     protected $_courseid;
45     /**
46      * Constructor.
47      *
48      * @param int $courseid Course ID.
49      */
50     public function __construct($courseid) {
51         $this->_courseid = $courseid;
52     }
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     }
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;
72         return $DB->get_record('tool_recyclebin_course', array(
73             'id' => $itemid
74         ), '*', MUST_EXIST);
75     }
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;
85         return $DB->get_records('tool_recyclebin_course', array(
86             'courseid' => $this->_courseid
87         ));
88     }
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;
99         require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
101         // Get more information.
102         $modinfo = get_fast_modinfo($cm->course);
104         if (!isset($modinfo->cms[$cm->id])) {
105             return; // Can't continue without the module information.
106         }
108         $cminfo = $modinfo->cms[$cm->id];
110         // Check backup/restore support.
111         if (!plugin_supports('mod', $cminfo->modname , FEATURE_BACKUP_MOODLE2)) {
112             return;
113         }
115         // Backup the activity.
116         $user = get_admin();
117         $controller = new \backup_controller(
118             \backup::TYPE_1ACTIVITY,
119             $cm->id,
120             \backup::FORMAT_MOODLE,
121             \backup::INTERACTIVE_NO,
122             \backup::MODE_GENERAL,
123             $user->id
124         );
125         $controller->execute_plan();
127         // Grab the result.
128         $result = $controller->get_results();
129         if (!isset($result['backup_destination'])) {
130             throw new \moodle_exception('Failed to backup activity prior to deletion.');
131         }
133         // Grab the filename.
134         $file = $result['backup_destination'];
135         if (!$file->get_contenthash()) {
136             throw new \moodle_exception('Failed to backup activity prior to deletion (invalid file).');
137         }
139         // Record the activity, get an ID.
140         $activity = new \stdClass();
141         $activity->courseid = $cm->course;
142         $activity->section = $cm->section;
143         $activity->module = $cm->module;
144         $activity->name = $cminfo->name;
145         $activity->timecreated = time();
146         $binid = $DB->insert_record('tool_recyclebin_course', $activity);
148         // Create the location we want to copy this file to.
149         $filerecord = array(
150             'contextid' => \context_course::instance($this->_courseid)->id,
151             'component' => 'tool_recyclebin',
152             'filearea' => TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA,
153             'itemid' => $binid,
154             'timemodified' => time()
155         );
157         // Move the file to our own special little place.
158         $fs = get_file_storage();
159         if (!$fs->create_file_from_storedfile($filerecord, $file)) {
160             // Failed, cleanup first.
161             $DB->delete_records('tool_recyclebin_course', array(
162                 'id' => $binid
163             ));
165             throw new \moodle_exception("Failed to copy backup file to recyclebin.");
166         }
168         // Delete the old file.
169         $file->delete();
171         // Fire event.
172         $event = \tool_recyclebin\event\course_bin_item_created::create(array(
173             'objectid' => $binid,
174             'context' => \context_course::instance($cm->course)
175         ));
176         $event->trigger();
177     }
179     /**
180      * Restore an item from the recycle bin.
181      *
182      * @param \stdClass $item The item database record
183      * @throws \moodle_exception
184      */
185     public function restore_item($item) {
186         global $CFG, $OUTPUT, $PAGE;
188         require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
190         $user = get_admin();
192         // Grab the course context.
193         $context = \context_course::instance($this->_courseid);
195         // Get the files..
196         $fs = get_file_storage();
197         $files = $fs->get_area_files($context->id, 'tool_recyclebin', TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA, $item->id,
198             'itemid, filepath, filename', false);
200         if (empty($files)) {
201             throw new \moodle_exception('Invalid recycle bin item!');
202         }
204         if (count($files) > 1) {
205             throw new \moodle_exception('Too many files found!');
206         }
208         // Get the backup file.
209         $file = reset($files);
211         // Get a temp directory name and create it.
212         $tempdir = \restore_controller::get_tempdir_name($context->id, $user->id);
213         $fulltempdir = make_temp_directory('/backup/' . $tempdir);
215         // Extract the backup to tempdir.
216         $fb = get_file_packer('application/vnd.moodle.backup');
217         $fb->extract_to_pathname($file, $fulltempdir);
219         // Define the import.
220         $controller = new \restore_controller(
221             $tempdir,
222             $this->_courseid,
223             \backup::INTERACTIVE_NO,
224             \backup::MODE_GENERAL,
225             $user->id,
226             \backup::TARGET_EXISTING_ADDING
227         );
229         // Prechecks.
230         if (!$controller->execute_precheck()) {
231             $results = $controller->get_precheck_results();
233             // If errors are found then delete the file we created.
234             if (!empty($results['errors'])) {
235                 fulldelete($fulltempdir);
237                 echo $OUTPUT->header();
238                 $backuprenderer = $PAGE->get_renderer('core', 'backup');
239                 echo $backuprenderer->precheck_notices($results);
240                 echo $OUTPUT->continue_button(new \moodle_url('/course/view.php', array('id' => $this->_courseid)));
241                 echo $OUTPUT->footer();
242                 exit();
243             }
244         }
246         // Run the import.
247         $controller->execute_plan();
249         // Fire event.
250         $event = \tool_recyclebin\event\course_bin_item_restored::create(array(
251             'objectid' => $item->id,
252             'context' => $context
253         ));
254         $event->add_record_snapshot('tool_recyclebin_course', $item);
255         $event->trigger();
257         // Cleanup.
258         fulldelete($fulltempdir);
259         $this->delete_item($item);
260     }
262     /**
263      * Delete an item from the recycle bin.
264      *
265      * @param \stdClass $item The item database record
266      */
267     public function delete_item($item) {
268         global $DB;
270         // Grab the course context.
271         $context = \context_course::instance($this->_courseid);
273         // Delete the files.
274         $fs = get_file_storage();
275         $files = $fs->get_area_files($context->id, 'tool_recyclebin', TOOL_RECYCLEBIN_COURSE_BIN_FILEAREA, $item->id);
276         foreach ($files as $file) {
277             $file->delete();
278         }
280         // Delete the record.
281         $DB->delete_records('tool_recyclebin_course', array(
282             'id' => $item->id
283         ));
285         // The course might have been deleted, check we have a context.
286         $context = \context_course::instance($item->courseid, \IGNORE_MISSING);
287         if (!$context) {
288             return;
289         }
291         // Fire event.
292         $event = \tool_recyclebin\event\course_bin_item_deleted::create(array(
293             'objectid' => $item->id,
294             'context' => $context
295         ));
296         $event->add_record_snapshot('tool_recyclebin_course', $item);
297         $event->trigger();
298     }
300     /**
301      * Can we view items in this recycle bin?
302      *
303      * @return bool returns true if they can view, false if not
304      */
305     public function can_view() {
306         $context = \context_course::instance($this->_courseid);
307         return has_capability('tool/recyclebin:viewitems', $context);
308     }
310     /**
311      * Can we restore items in this recycle bin?
312      *
313      * @return bool returns true if they can restore, false if not
314      */
315     public function can_restore() {
316         $context = \context_course::instance($this->_courseid);
317         return has_capability('tool/recyclebin:restoreitems', $context);
318     }
320     /**
321      * Can we delete this?
322      *
323      * @return bool returns true if they can delete, false if not
324      */
325     public function can_delete() {
326         $context = \context_course::instance($this->_courseid);
327         return has_capability('tool/recyclebin:deleteitems', $context);
328     }