MDL-50490 cron: Prevent tasks from leaving uncommitted transactions
[moodle.git] / mod / imscp / lib.php
blob2304398f84a032f6134d0edc1900bffd2825a9be
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.
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 * Mandatory public API of imscp module
20 * @package mod_imscp
21 * @copyright 2009 Petr Skoda {@link http://skodak.org}
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 defined('MOODLE_INTERNAL') || die();
27 /**
28 * List of features supported in IMS CP module
29 * @param string $feature FEATURE_xx constant for requested feature
30 * @return mixed True if module supports feature, false if not, null if doesn't know
32 function imscp_supports($feature) {
33 switch($feature) {
34 case FEATURE_MOD_ARCHETYPE: return MOD_ARCHETYPE_RESOURCE;
35 case FEATURE_GROUPS: return false;
36 case FEATURE_GROUPINGS: return false;
37 case FEATURE_MOD_INTRO: return true;
38 case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
39 case FEATURE_GRADE_HAS_GRADE: return false;
40 case FEATURE_GRADE_OUTCOMES: return false;
41 case FEATURE_BACKUP_MOODLE2: return true;
42 case FEATURE_SHOW_DESCRIPTION: return true;
44 default: return null;
48 /**
49 * Returns all other caps used in module
50 * @return array
52 function imscp_get_extra_capabilities() {
53 return array('moodle/site:accessallgroups');
56 /**
57 * This function is used by the reset_course_userdata function in moodlelib.
59 * @param stdClass $data the data submitted from the reset course.
60 * @return array status array
62 function imscp_reset_userdata($data) {
63 return array();
66 /**
67 * List the actions that correspond to a view of this module.
68 * This is used by the participation report.
70 * Note: This is not used by new logging system. Event with
71 * crud = 'r' and edulevel = LEVEL_PARTICIPATING will
72 * be considered as view action.
74 * @return array
76 function imscp_get_view_actions() {
77 return array('view', 'view all');
80 /**
81 * List the actions that correspond to a post of this module.
82 * This is used by the participation report.
84 * Note: This is not used by new logging system. Event with
85 * crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING
86 * will be considered as post action.
88 * @return array
90 function imscp_get_post_actions() {
91 return array('update', 'add');
94 /**
95 * Add imscp instance.
96 * @param object $data
97 * @param object $mform
98 * @return int new imscp instance id
100 function imscp_add_instance($data, $mform) {
101 global $CFG, $DB;
102 require_once("$CFG->dirroot/mod/imscp/locallib.php");
104 $cmid = $data->coursemodule;
106 $data->timemodified = time();
107 $data->revision = 1;
108 $data->structure = null;
110 $data->id = $DB->insert_record('imscp', $data);
112 // We need to use context now, so we need to make sure all needed info is already in db.
113 $DB->set_field('course_modules', 'instance', $data->id, array('id' => $cmid));
114 $context = context_module::instance($cmid);
115 $imscp = $DB->get_record('imscp', array('id' => $data->id), '*', MUST_EXIST);
117 if (!empty($data->package)) {
118 // Save uploaded files to 'backup' filearea.
119 $fs = get_file_storage();
120 $fs->delete_area_files($context->id, 'mod_imscp', 'backup', 1);
121 file_save_draft_area_files($data->package, $context->id, 'mod_imscp', 'backup',
122 1, array('subdirs' => 0, 'maxfiles' => 1));
123 // Get filename of zip that was uploaded.
124 $files = $fs->get_area_files($context->id, 'mod_imscp', 'backup', 1, '', false);
125 if ($files) {
126 // Extract package content to 'content' filearea.
127 $package = reset($files);
128 $packer = get_file_packer('application/zip');
129 $package->extract_to_storage($packer, $context->id, 'mod_imscp', 'content', 1, '/');
130 $structure = imscp_parse_structure($imscp, $context);
131 $imscp->structure = is_array($structure) ? serialize($structure) : null;
132 $DB->update_record('imscp', $imscp);
136 return $data->id;
140 * Update imscp instance.
141 * @param object $data
142 * @param object $mform
143 * @return bool true
145 function imscp_update_instance($data, $mform) {
146 global $CFG, $DB;
147 require_once("$CFG->dirroot/mod/imscp/locallib.php");
149 $cmid = $data->coursemodule;
151 $data->timemodified = time();
152 $data->id = $data->instance;
153 $data->structure = null; // Better reparse structure after each update.
155 $DB->update_record('imscp', $data);
157 $context = context_module::instance($cmid);
158 $imscp = $DB->get_record('imscp', array('id' => $data->id), '*', MUST_EXIST);
160 if (!empty($data->package) && ($draftareainfo = file_get_draft_area_info($data->package)) &&
161 $draftareainfo['filecount']) {
162 $fs = get_file_storage();
164 $imscp->revision++;
165 $DB->update_record('imscp', $imscp);
167 // Get a list of existing packages before adding new package.
168 if ($imscp->keepold > -1) {
169 $packages = $fs->get_area_files($context->id, 'mod_imscp', 'backup', false, "itemid ASC", false);
170 } else {
171 $packages = array();
174 file_save_draft_area_files($data->package, $context->id, 'mod_imscp', 'backup',
175 $imscp->revision, array('subdirs' => 0, 'maxfiles' => 1));
176 $files = $fs->get_area_files($context->id, 'mod_imscp', 'backup', $imscp->revision, '', false);
177 $package = reset($files);
179 // Purge all extracted content.
180 $fs->delete_area_files($context->id, 'mod_imscp', 'content');
182 // Extract package content.
183 if ($package) {
184 $packer = get_file_packer('application/zip');
185 $package->extract_to_storage($packer, $context->id, 'mod_imscp', 'content', $imscp->revision, '/');
188 // Cleanup old package files, keep current + keep old.
189 while ($packages and (count($packages) > $imscp->keepold)) {
190 $package = array_shift($packages);
191 $fs->delete_area_files($context->id, 'mod_imscp', 'backup', $package->get_itemid());
195 $structure = imscp_parse_structure($imscp, $context);
196 $imscp->structure = is_array($structure) ? serialize($structure) : null;
197 $DB->update_record('imscp', $imscp);
199 return true;
203 * Delete imscp instance.
204 * @param int $id
205 * @return bool true
207 function imscp_delete_instance($id) {
208 global $DB;
210 if (!$imscp = $DB->get_record('imscp', array('id' => $id))) {
211 return false;
214 // Note: all context files are deleted automatically.
216 $DB->delete_records('imscp', array('id' => $imscp->id));
218 return true;
222 * Lists all browsable file areas
224 * @package mod_imscp
225 * @category files
226 * @param stdClass $course course object
227 * @param stdClass $cm course module object
228 * @param stdClass $context context object
229 * @return array
231 function imscp_get_file_areas($course, $cm, $context) {
232 $areas = array();
234 $areas['content'] = get_string('areacontent', 'imscp');
235 $areas['backup'] = get_string('areabackup', 'imscp');
237 return $areas;
241 * File browsing support for imscp module ontent area.
243 * @package mod_imscp
244 * @category files
245 * @param stdClass $browser file browser
246 * @param stdClass $areas file areas
247 * @param stdClass $course course object
248 * @param stdClass $cm course module object
249 * @param stdClass $context context object
250 * @param string $filearea file area
251 * @param int $itemid item ID
252 * @param string $filepath file path
253 * @param string $filename file name
254 * @return file_info instance or null if not found
256 function imscp_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
257 global $CFG, $DB;
259 // Note: imscp_intro handled in file_browser automatically.
261 if (!has_capability('moodle/course:managefiles', $context)) {
262 // No peeking here for students!
263 return null;
266 if ($filearea !== 'content' and $filearea !== 'backup') {
267 return null;
270 require_once("$CFG->dirroot/mod/imscp/locallib.php");
272 if (is_null($itemid)) {
273 return new imscp_file_info($browser, $course, $cm, $context, $areas, $filearea, $itemid);
276 $fs = get_file_storage();
277 $filepath = is_null($filepath) ? '/' : $filepath;
278 $filename = is_null($filename) ? '.' : $filename;
279 if (!$storedfile = $fs->get_file($context->id, 'mod_imscp', $filearea, $itemid, $filepath, $filename)) {
280 return null;
283 // Do not allow manual modification of any files!
284 $urlbase = $CFG->wwwroot.'/pluginfile.php';
285 return new file_info_stored($browser, $context, $storedfile, $urlbase, $itemid, true, true, false, false); // No writing here!
289 * Serves the imscp files.
291 * @package mod_imscp
292 * @category files
293 * @param stdClass $course course object
294 * @param stdClass $cm course module object
295 * @param stdClass $context context object
296 * @param string $filearea file area
297 * @param array $args extra arguments
298 * @param bool $forcedownload whether or not force download
299 * @param array $options additional options affecting the file serving
300 * @return bool false if file not found, does not return if found - justsend the file
302 function imscp_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
303 global $CFG, $DB;
305 if ($context->contextlevel != CONTEXT_MODULE) {
306 return false;
309 require_login($course, true, $cm);
311 if ($filearea === 'content') {
312 if (!has_capability('mod/imscp:view', $context)) {
313 return false;
315 $revision = array_shift($args);
316 $fs = get_file_storage();
317 $relativepath = implode('/', $args);
318 if ($relativepath === 'imsmanifest.xml') {
319 if (!has_capability('moodle/course:managefiles', $context)) {
320 // No stealing of detailed package info.
321 return false;
324 $fullpath = "/$context->id/mod_imscp/$filearea/$revision/$relativepath";
325 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
326 return false;
329 // Finally send the file.
330 send_stored_file($file, null, 0, $forcedownload, $options);
332 } else if ($filearea === 'backup') {
333 if (!has_capability('moodle/course:managefiles', $context)) {
334 // No stealing of package backups.
335 return false;
337 $revision = array_shift($args);
338 $fs = get_file_storage();
339 $relativepath = implode('/', $args);
340 $fullpath = "/$context->id/mod_imscp/$filearea/$revision/$relativepath";
341 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
342 return false;
345 // Finally send the file.
346 send_stored_file($file, null, 0, $forcedownload, $options);
348 } else {
349 return false;
354 * Return a list of page types
355 * @param string $pagetype current page type
356 * @param stdClass $parentcontext Block's parent context
357 * @param stdClass $currentcontext Current context of block
358 * @return array $modulepagetype list
360 function imscp_page_type_list($pagetype, $parentcontext, $currentcontext) {
361 $modulepagetype = array('mod-imscp-*' => get_string('page-mod-imscp-x', 'imscp'));
362 return $modulepagetype;
366 * Export imscp resource contents
368 * @param stdClass $cm Course module object
369 * @param string $baseurl Base URL for file downloads
370 * @return array of file content
372 function imscp_export_contents($cm, $baseurl) {
373 global $DB;
375 $contents = array();
376 $context = context_module::instance($cm->id);
378 $imscp = $DB->get_record('imscp', array('id' => $cm->instance), '*', MUST_EXIST);
380 // We export the IMSCP structure as json encoded string.
381 $structure = array();
382 $structure['type'] = 'content';
383 $structure['filename'] = 'structure';
384 $structure['filepath'] = '/';
385 $structure['filesize'] = 0;
386 $structure['fileurl'] = null;
387 $structure['timecreated'] = $imscp->timemodified;
388 $structure['timemodified'] = $imscp->timemodified;
389 $structure['content'] = json_encode(unserialize($imscp->structure));
390 $structure['sortorder'] = 0;
391 $structure['userid'] = null;
392 $structure['author'] = null;
393 $structure['license'] = null;
394 $contents[] = $structure;
396 // Area files.
397 $fs = get_file_storage();
398 $files = $fs->get_area_files($context->id, 'mod_imscp', 'content', $imscp->revision, 'id ASC', false);
399 foreach ($files as $fileinfo) {
400 $file = array();
401 $file['type'] = 'file';
402 $file['filename'] = $fileinfo->get_filename();
403 $file['filepath'] = $fileinfo->get_filepath();
404 $file['filesize'] = $fileinfo->get_filesize();
405 $file['fileurl'] = moodle_url::make_webservice_pluginfile_url(
406 $context->id, 'mod_imscp', 'content', $imscp->revision,
407 $fileinfo->get_filepath(), $fileinfo->get_filename())->out(false);
408 $file['timecreated'] = $fileinfo->get_timecreated();
409 $file['timemodified'] = $fileinfo->get_timemodified();
410 $file['sortorder'] = $fileinfo->get_sortorder();
411 $file['userid'] = $fileinfo->get_userid();
412 $file['author'] = $fileinfo->get_author();
413 $file['license'] = $fileinfo->get_license();
414 $contents[] = $file;
417 return $contents;