See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 401 and 402] [Versions 401 and 403]
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 * Mandatory public API of imscp module 19 * 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 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 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 or string for the module purpose. 31 */ 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; 43 case FEATURE_MOD_PURPOSE: return MOD_PURPOSE_CONTENT; 44 45 default: return null; 46 } 47 } 48 49 /** 50 * This function is used by the reset_course_userdata function in moodlelib. 51 * 52 * @param stdClass $data the data submitted from the reset course. 53 * @return array status array 54 */ 55 function imscp_reset_userdata($data) { 56 57 // Any changes to the list of dates that needs to be rolled should be same during course restore and course reset. 58 // See MDL-9367. 59 60 return array(); 61 } 62 63 /** 64 * List the actions that correspond to a view of this module. 65 * This is used by the participation report. 66 * 67 * Note: This is not used by new logging system. Event with 68 * crud = 'r' and edulevel = LEVEL_PARTICIPATING will 69 * be considered as view action. 70 * 71 * @return array 72 */ 73 function imscp_get_view_actions() { 74 return array('view', 'view all'); 75 } 76 77 /** 78 * List the actions that correspond to a post of this module. 79 * This is used by the participation report. 80 * 81 * Note: This is not used by new logging system. Event with 82 * crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING 83 * will be considered as post action. 84 * 85 * @return array 86 */ 87 function imscp_get_post_actions() { 88 return array('update', 'add'); 89 } 90 91 /** 92 * Add imscp instance. 93 * @param object $data 94 * @param object $mform 95 * @return int new imscp instance id 96 */ 97 function imscp_add_instance($data, $mform) { 98 global $CFG, $DB; 99 require_once("$CFG->dirroot/mod/imscp/locallib.php"); 100 101 $cmid = $data->coursemodule; 102 103 $data->timemodified = time(); 104 $data->revision = 1; 105 $data->structure = null; 106 107 $data->id = $DB->insert_record('imscp', $data); 108 109 // We need to use context now, so we need to make sure all needed info is already in db. 110 $DB->set_field('course_modules', 'instance', $data->id, array('id' => $cmid)); 111 $context = context_module::instance($cmid); 112 $imscp = $DB->get_record('imscp', array('id' => $data->id), '*', MUST_EXIST); 113 114 if (!empty($data->package)) { 115 // Save uploaded files to 'backup' filearea. 116 $fs = get_file_storage(); 117 $fs->delete_area_files($context->id, 'mod_imscp', 'backup', 1); 118 file_save_draft_area_files($data->package, $context->id, 'mod_imscp', 'backup', 119 1, array('subdirs' => 0, 'maxfiles' => 1)); 120 // Get filename of zip that was uploaded. 121 $files = $fs->get_area_files($context->id, 'mod_imscp', 'backup', 1, '', false); 122 if ($files) { 123 // Extract package content to 'content' filearea. 124 $package = reset($files); 125 $packer = get_file_packer('application/zip'); 126 $package->extract_to_storage($packer, $context->id, 'mod_imscp', 'content', 1, '/'); 127 $structure = imscp_parse_structure($imscp, $context); 128 $imscp->structure = is_array($structure) ? serialize($structure) : null; 129 $DB->update_record('imscp', $imscp); 130 } 131 } 132 133 $completiontimeexpected = !empty($data->completionexpected) ? $data->completionexpected : null; 134 \core_completion\api::update_completion_date_event($cmid, 'imscp', $data->id, $completiontimeexpected); 135 136 return $data->id; 137 } 138 139 /** 140 * Update imscp instance. 141 * @param object $data 142 * @param object $mform 143 * @return bool true 144 */ 145 function imscp_update_instance($data, $mform) { 146 global $CFG, $DB; 147 require_once("$CFG->dirroot/mod/imscp/locallib.php"); 148 149 $cmid = $data->coursemodule; 150 151 $data->timemodified = time(); 152 $data->id = $data->instance; 153 $data->structure = null; // Better reparse structure after each update. 154 155 $DB->update_record('imscp', $data); 156 157 $context = context_module::instance($cmid); 158 $imscp = $DB->get_record('imscp', array('id' => $data->id), '*', MUST_EXIST); 159 160 if (!empty($data->package) && ($draftareainfo = file_get_draft_area_info($data->package)) && 161 $draftareainfo['filecount']) { 162 $fs = get_file_storage(); 163 164 $imscp->revision++; 165 $DB->update_record('imscp', $imscp); 166 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(); 172 } 173 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); 178 179 // Purge all extracted content. 180 $fs->delete_area_files($context->id, 'mod_imscp', 'content'); 181 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, '/'); 186 } 187 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()); 192 } 193 } 194 195 $structure = imscp_parse_structure($imscp, $context); 196 $imscp->structure = is_array($structure) ? serialize($structure) : null; 197 $DB->update_record('imscp', $imscp); 198 199 $completiontimeexpected = !empty($data->completionexpected) ? $data->completionexpected : null; 200 \core_completion\api::update_completion_date_event($cmid, 'imscp', $imscp->id, $completiontimeexpected); 201 202 return true; 203 } 204 205 /** 206 * Delete imscp instance. 207 * @param int $id 208 * @return bool true 209 */ 210 function imscp_delete_instance($id) { 211 global $DB; 212 213 if (!$imscp = $DB->get_record('imscp', array('id' => $id))) { 214 return false; 215 } 216 217 $cm = get_coursemodule_from_instance('imscp', $id); 218 \core_completion\api::update_completion_date_event($cm->id, 'imscp', $id, null); 219 220 // Note: all context files are deleted automatically. 221 222 $DB->delete_records('imscp', array('id' => $imscp->id)); 223 224 return true; 225 } 226 227 /** 228 * Lists all browsable file areas 229 * 230 * @package mod_imscp 231 * @category files 232 * @param stdClass $course course object 233 * @param stdClass $cm course module object 234 * @param stdClass $context context object 235 * @return array 236 */ 237 function imscp_get_file_areas($course, $cm, $context) { 238 $areas = array(); 239 240 $areas['content'] = get_string('areacontent', 'imscp'); 241 $areas['backup'] = get_string('areabackup', 'imscp'); 242 243 return $areas; 244 } 245 246 /** 247 * File browsing support for imscp module ontent area. 248 * 249 * @package mod_imscp 250 * @category files 251 * @param stdClass $browser file browser 252 * @param stdClass $areas file areas 253 * @param stdClass $course course object 254 * @param stdClass $cm course module object 255 * @param stdClass $context context object 256 * @param string $filearea file area 257 * @param int $itemid item ID 258 * @param string $filepath file path 259 * @param string $filename file name 260 * @return file_info instance or null if not found 261 */ 262 function imscp_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) { 263 global $CFG, $DB; 264 265 // Note: imscp_intro handled in file_browser automatically. 266 267 if (!has_capability('moodle/course:managefiles', $context)) { 268 // No peeking here for students! 269 return null; 270 } 271 272 if ($filearea !== 'content' and $filearea !== 'backup') { 273 return null; 274 } 275 276 require_once("$CFG->dirroot/mod/imscp/locallib.php"); 277 278 if (is_null($itemid)) { 279 return new imscp_file_info($browser, $course, $cm, $context, $areas, $filearea, $itemid); 280 } 281 282 $fs = get_file_storage(); 283 $filepath = is_null($filepath) ? '/' : $filepath; 284 $filename = is_null($filename) ? '.' : $filename; 285 if (!$storedfile = $fs->get_file($context->id, 'mod_imscp', $filearea, $itemid, $filepath, $filename)) { 286 return null; 287 } 288 289 // Do not allow manual modification of any files! 290 $urlbase = $CFG->wwwroot.'/pluginfile.php'; 291 return new file_info_stored($browser, $context, $storedfile, $urlbase, $itemid, true, true, false, false); // No writing here! 292 } 293 294 /** 295 * Serves the imscp files. 296 * 297 * @package mod_imscp 298 * @category files 299 * @param stdClass $course course object 300 * @param stdClass $cm course module object 301 * @param stdClass $context context object 302 * @param string $filearea file area 303 * @param array $args extra arguments 304 * @param bool $forcedownload whether or not force download 305 * @param array $options additional options affecting the file serving 306 * @return bool false if file not found, does not return if found - justsend the file 307 */ 308 function imscp_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) { 309 global $CFG, $DB; 310 311 if ($context->contextlevel != CONTEXT_MODULE) { 312 return false; 313 } 314 315 require_login($course, true, $cm); 316 317 if ($filearea === 'content') { 318 if (!has_capability('mod/imscp:view', $context)) { 319 return false; 320 } 321 $revision = array_shift($args); 322 $fs = get_file_storage(); 323 $relativepath = implode('/', $args); 324 if ($relativepath === 'imsmanifest.xml') { 325 if (!has_capability('moodle/course:managefiles', $context)) { 326 // No stealing of detailed package info. 327 return false; 328 } 329 } 330 $fullpath = "/$context->id/mod_imscp/$filearea/$revision/$relativepath"; 331 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 332 return false; 333 } 334 335 // Finally send the file. 336 send_stored_file($file, null, 0, $forcedownload, $options); 337 338 } else if ($filearea === 'backup') { 339 if (!has_capability('moodle/course:managefiles', $context)) { 340 // No stealing of package backups. 341 return false; 342 } 343 $revision = array_shift($args); 344 $fs = get_file_storage(); 345 $relativepath = implode('/', $args); 346 $fullpath = "/$context->id/mod_imscp/$filearea/$revision/$relativepath"; 347 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 348 return false; 349 } 350 351 // Finally send the file. 352 send_stored_file($file, null, 0, $forcedownload, $options); 353 354 } else { 355 return false; 356 } 357 } 358 359 /** 360 * Return a list of page types 361 * @param string $pagetype current page type 362 * @param stdClass $parentcontext Block's parent context 363 * @param stdClass $currentcontext Current context of block 364 * @return array $modulepagetype list 365 */ 366 function imscp_page_type_list($pagetype, $parentcontext, $currentcontext) { 367 $modulepagetype = array('mod-imscp-*' => get_string('page-mod-imscp-x', 'imscp')); 368 return $modulepagetype; 369 } 370 371 /** 372 * Export imscp resource contents 373 * 374 * @param stdClass $cm Course module object 375 * @param string $baseurl Base URL for file downloads 376 * @return array of file content 377 */ 378 function imscp_export_contents($cm, $baseurl) { 379 global $DB; 380 381 $contents = array(); 382 $context = context_module::instance($cm->id); 383 384 $imscp = $DB->get_record('imscp', array('id' => $cm->instance), '*', MUST_EXIST); 385 386 // We export the IMSCP structure as json encoded string. 387 $structure = array(); 388 $structure['type'] = 'content'; 389 $structure['filename'] = 'structure'; 390 $structure['filepath'] = '/'; 391 $structure['filesize'] = 0; 392 $structure['fileurl'] = null; 393 $structure['timecreated'] = $imscp->timemodified; 394 $structure['timemodified'] = $imscp->timemodified; 395 $structure['content'] = json_encode(unserialize_array($imscp->structure)); 396 $structure['sortorder'] = 0; 397 $structure['userid'] = null; 398 $structure['author'] = null; 399 $structure['license'] = null; 400 $contents[] = $structure; 401 402 // Area files. 403 $fs = get_file_storage(); 404 $files = $fs->get_area_files($context->id, 'mod_imscp', 'content', $imscp->revision, 'id ASC', false); 405 foreach ($files as $fileinfo) { 406 $file = array(); 407 $file['type'] = 'file'; 408 $file['filename'] = $fileinfo->get_filename(); 409 $file['filepath'] = $fileinfo->get_filepath(); 410 $file['filesize'] = $fileinfo->get_filesize(); 411 $file['fileurl'] = moodle_url::make_webservice_pluginfile_url( 412 $context->id, 'mod_imscp', 'content', $imscp->revision, 413 $fileinfo->get_filepath(), $fileinfo->get_filename())->out(false); 414 $file['timecreated'] = $fileinfo->get_timecreated(); 415 $file['timemodified'] = $fileinfo->get_timemodified(); 416 $file['sortorder'] = $fileinfo->get_sortorder(); 417 $file['userid'] = $fileinfo->get_userid(); 418 $file['author'] = $fileinfo->get_author(); 419 $file['license'] = $fileinfo->get_license(); 420 $file['mimetype'] = $fileinfo->get_mimetype(); 421 $file['isexternalfile'] = $fileinfo->is_external_file(); 422 if ($file['isexternalfile']) { 423 $file['repositorytype'] = $fileinfo->get_repository_type(); 424 } 425 $contents[] = $file; 426 } 427 428 return $contents; 429 } 430 431 /** 432 * Mark the activity completed (if required) and trigger the course_module_viewed event. 433 * 434 * @param stdClass $imscp imscp object 435 * @param stdClass $course course object 436 * @param stdClass $cm course module object 437 * @param stdClass $context context object 438 * @since Moodle 3.0 439 */ 440 function imscp_view($imscp, $course, $cm, $context) { 441 442 // Trigger course_module_viewed event. 443 $params = array( 444 'context' => $context, 445 'objectid' => $imscp->id 446 ); 447 448 $event = \mod_imscp\event\course_module_viewed::create($params); 449 $event->add_record_snapshot('course_modules', $cm); 450 $event->add_record_snapshot('course', $course); 451 $event->add_record_snapshot('imscp', $imscp); 452 $event->trigger(); 453 454 // Completion. 455 $completion = new completion_info($course); 456 $completion->set_module_viewed($cm); 457 } 458 459 /** 460 * Check if the module has any update that affects the current user since a given time. 461 * 462 * @param cm_info $cm course module data 463 * @param int $from the time to check updates from 464 * @param array $filter if we need to check only specific updates 465 * @return stdClass an object with the different type of areas indicating if they were updated or not 466 * @since Moodle 3.2 467 */ 468 function imscp_check_updates_since(cm_info $cm, $from, $filter = array()) { 469 $updates = course_check_module_updates_since($cm, $from, array('content'), $filter); 470 return $updates; 471 } 472 473 /** 474 * This function receives a calendar event and returns the action associated with it, or null if there is none. 475 * 476 * This is used by block_myoverview in order to display the event appropriately. If null is returned then the event 477 * is not displayed on the block. 478 * 479 * @param calendar_event $event 480 * @param \core_calendar\action_factory $factory 481 * @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default). 482 * @return \core_calendar\local\event\entities\action_interface|null 483 */ 484 function mod_imscp_core_calendar_provide_event_action(calendar_event $event, 485 \core_calendar\action_factory $factory, 486 int $userid = 0) { 487 $cm = get_fast_modinfo($event->courseid, $userid)->instances['imscp'][$event->instance]; 488 489 if (!$cm->uservisible) { 490 // The module is not visible to the user for any reason. 491 return null; 492 } 493 494 $completion = new \completion_info($cm->get_course()); 495 496 $completiondata = $completion->get_data($cm, false, $userid); 497 498 if ($completiondata->completionstate != COMPLETION_INCOMPLETE) { 499 return null; 500 } 501 502 return $factory->create_instance( 503 get_string('view'), 504 new \moodle_url('/mod/imscp/view.php', ['id' => $cm->id]), 505 1, 506 true 507 ); 508 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body