/** * Check if the module has any update that affects the current user since a given time. * * @param cm_info $cm course module data * @param int $from the time to check updates from * @param array $filter if we need to check only specific updates * @return stdClass an object with the different type of areas indicating if they were updated or not * @since Moodle 3.2 */ function scorm_check_updates_since(cm_info $cm, $from, $filter = array()) { global $DB, $USER, $CFG; require_once $CFG->dirroot . '/mod/scorm/locallib.php'; $scorm = $DB->get_record($cm->modname, array('id' => $cm->instance), '*', MUST_EXIST); $updates = new stdClass(); list($available, $warnings) = scorm_get_availability_status($scorm, true, $cm->context); if (!$available) { return $updates; } $updates = course_check_module_updates_since($cm, $from, array('package'), $filter); $updates->tracks = (object) array('updated' => false); $select = 'scormid = ? AND userid = ? AND timemodified > ?'; $params = array($scorm->id, $USER->id, $from); $tracks = $DB->get_records_select('scorm_scoes_track', $select, $params, '', 'id'); if (!empty($tracks)) { $updates->tracks->updated = true; $updates->tracks->itemids = array_keys($tracks); } return $updates; }
/** * Returns a list of scorms in a provided list of courses, * if no list is provided all scorms that the user can view will be returned. * * @param array $courseids the course ids * @return array the scorm details * @since Moodle 3.0 */ public static function get_scorms_by_courses($courseids = array()) { global $CFG; $returnedscorms = array(); $warnings = array(); $params = self::validate_parameters(self::get_scorms_by_courses_parameters(), array('courseids' => $courseids)); $courses = array(); if (empty($params['courseids'])) { $courses = enrol_get_my_courses(); $params['courseids'] = array_keys($courses); } // Ensure there are courseids to loop through. if (!empty($params['courseids'])) { list($courses, $warnings) = external_util::validate_courses($params['courseids'], $courses); // Get the scorms in this course, this function checks users visibility permissions. // We can avoid then additional validate_context calls. $scorms = get_all_instances_in_courses("scorm", $courses); $fs = get_file_storage(); foreach ($scorms as $scorm) { $context = context_module::instance($scorm->coursemodule); // Entry to return. $module = array(); // First, we return information that any user can see in (or can deduce from) the web interface. $module['id'] = $scorm->id; $module['coursemodule'] = $scorm->coursemodule; $module['course'] = $scorm->course; $module['name'] = external_format_string($scorm->name, $context->id); list($module['intro'], $module['introformat']) = external_format_text($scorm->intro, $scorm->introformat, $context->id, 'mod_scorm', 'intro', $scorm->id); // Check if the SCORM open and return warnings if so. list($open, $openwarnings) = scorm_get_availability_status($scorm, true, $context); if (!$open) { foreach ($openwarnings as $warningkey => $warningdata) { $warnings[] = array('item' => 'scorm', 'itemid' => $scorm->id, 'warningcode' => $warningkey, 'message' => get_string($warningkey, 'scorm', $warningdata)); } } else { $module['packagesize'] = 0; // SCORM size. if ($scorm->scormtype === SCORM_TYPE_LOCAL or $scorm->scormtype === SCORM_TYPE_LOCALSYNC) { if ($packagefile = $fs->get_file($context->id, 'mod_scorm', 'package', 0, '/', $scorm->reference)) { $module['packagesize'] = $packagefile->get_filesize(); // Download URL. $module['packageurl'] = moodle_url::make_webservice_pluginfile_url($context->id, 'mod_scorm', 'package', 0, '/', $scorm->reference)->out(false); } } $module['protectpackagedownloads'] = get_config('scorm', 'protectpackagedownloads'); $viewablefields = array('version', 'maxgrade', 'grademethod', 'whatgrade', 'maxattempt', 'forcecompleted', 'forcenewattempt', 'lastattemptlock', 'displayattemptstatus', 'displaycoursestructure', 'sha1hash', 'md5hash', 'revision', 'launch', 'skipview', 'hidebrowse', 'hidetoc', 'nav', 'navpositionleft', 'navpositiontop', 'auto', 'popup', 'width', 'height', 'timeopen', 'timeclose', 'displayactivityname', 'scormtype', 'reference'); // Check additional permissions for returning optional private settings. if (has_capability('moodle/course:manageactivities', $context)) { $additionalfields = array('updatefreq', 'options', 'completionstatusrequired', 'completionscorerequired', 'autocommit', 'timemodified', 'section', 'visible', 'groupmode', 'groupingid'); $viewablefields = array_merge($viewablefields, $additionalfields); } foreach ($viewablefields as $field) { $module[$field] = $scorm->{$field}; } } $returnedscorms[] = $module; } } $result = array(); $result['scorms'] = $returnedscorms; $result['warnings'] = $warnings; return $result; }
/** * Test scorm_get_availability_status and scorm_require_available * @return void */ public function test_scorm_check_and_require_available() { global $DB; // Set to the student user. self::setUser($this->student); // Usual case. list($status, $warnings) = scorm_get_availability_status($this->scorm, false); $this->assertEquals(true, $status); $this->assertCount(0, $warnings); // SCORM not open. $this->scorm->timeopen = time() + DAYSECS; list($status, $warnings) = scorm_get_availability_status($this->scorm, false); $this->assertEquals(false, $status); $this->assertCount(1, $warnings); // SCORM closed. $this->scorm->timeopen = 0; $this->scorm->timeclose = time() - DAYSECS; list($status, $warnings) = scorm_get_availability_status($this->scorm, false); $this->assertEquals(false, $status); $this->assertCount(1, $warnings); // SCORM not open and closed. $this->scorm->timeopen = time() + DAYSECS; list($status, $warnings) = scorm_get_availability_status($this->scorm, false); $this->assertEquals(false, $status); $this->assertCount(2, $warnings); // Now additional checkings with different parameters values. list($status, $warnings) = scorm_get_availability_status($this->scorm, true, $this->context); $this->assertEquals(false, $status); $this->assertCount(2, $warnings); // SCORM not open. $this->scorm->timeopen = time() + DAYSECS; $this->scorm->timeclose = 0; list($status, $warnings) = scorm_get_availability_status($this->scorm, true, $this->context); $this->assertEquals(false, $status); $this->assertCount(1, $warnings); // SCORM closed. $this->scorm->timeopen = 0; $this->scorm->timeclose = time() - DAYSECS; list($status, $warnings) = scorm_get_availability_status($this->scorm, true, $this->context); $this->assertEquals(false, $status); $this->assertCount(1, $warnings); // SCORM not open and closed. $this->scorm->timeopen = time() + DAYSECS; list($status, $warnings) = scorm_get_availability_status($this->scorm, true, $this->context); $this->assertEquals(false, $status); $this->assertCount(2, $warnings); // As teacher now. self::setUser($this->teacher); // SCORM not open and closed. $this->scorm->timeopen = time() + DAYSECS; list($status, $warnings) = scorm_get_availability_status($this->scorm, false); $this->assertEquals(false, $status); $this->assertCount(2, $warnings); // Now, we use the special capability. // SCORM not open and closed. $this->scorm->timeopen = time() + DAYSECS; list($status, $warnings) = scorm_get_availability_status($this->scorm, true, $this->context); $this->assertEquals(true, $status); $this->assertCount(0, $warnings); // Check exceptions does not broke anything. scorm_require_available($this->scorm, true, $this->context); // Now, expect exceptions. $this->setExpectedException('moodle_exception', get_string("notopenyet", "scorm", userdate($this->scorm->timeopen))); // Now as student other condition. self::setUser($this->student); $this->scorm->timeopen = 0; $this->scorm->timeclose = time() - DAYSECS; $this->setExpectedException('moodle_exception', get_string("expired", "scorm", userdate($this->scorm->timeclose))); scorm_require_available($this->scorm, false); }
if ($displaymode == 'popup') { $PAGE->set_pagelayout('embedded'); } else { $shortname = format_string($course->shortname, true, array('context' => $coursecontext)); $pagetitle = strip_tags("{$shortname}: " . format_string($scorm->name)); $PAGE->set_title($pagetitle); $PAGE->set_heading($course->fullname); } if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', context_module::instance($cm->id))) { echo $OUTPUT->header(); notice(get_string("activityiscurrentlyhidden")); echo $OUTPUT->footer(); die; } // Check if SCORM available. list($available, $warnings) = scorm_get_availability_status($scorm); if (!$available) { $reason = current(array_keys($warnings)); echo $OUTPUT->header(); echo $OUTPUT->box(get_string($reason, "scorm", $warnings[$reason]), "generalbox boxaligncenter"); echo $OUTPUT->footer(); die; } // TOC processing $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR)); // Just to be safe. if (!file_exists($CFG->dirroot . '/mod/scorm/datamodels/' . $scorm->version . 'lib.php')) { $scorm->version = 'scorm_12'; } require_once $CFG->dirroot . '/mod/scorm/datamodels/' . $scorm->version . 'lib.php'; $result = scorm_get_toc($USER, $scorm, $cm->id, TOCJSLINK, $currentorg, $scoid, $mode, $attempt, true, true);
/** * Requires a SCORM package to be available for the current user. * * @param stdClass $scorm SCORM record * @param boolean $checkviewreportcap Check the scorm:viewreport cap * @param stdClass $context Module context, required if $checkviewreportcap is set to true * @throws moodle_exception * @since Moodle 3.0 */ function scorm_require_available($scorm, $checkviewreportcap = false, $context = null) { list($available, $warnings) = scorm_get_availability_status($scorm, $checkviewreportcap, $context); if (!$available) { $reason = current(array_keys($warnings)); throw new moodle_exception($reason, 'scorm', '', $warnings[$reason]); } }
/** * Serves scorm content, introduction images and packages. Implements needed access control ;-) * * @package mod_scorm * @category files * @param stdClass $course course object * @param stdClass $cm course module object * @param stdClass $context context object * @param string $filearea file area * @param array $args extra arguments * @param bool $forcedownload whether or not force download * @param array $options additional options affecting the file serving * @return bool false if file not found, does not return if found - just send the file */ function scorm_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) { global $CFG, $DB; if ($context->contextlevel != CONTEXT_MODULE) { return false; } require_login($course, true, $cm); $canmanageactivity = has_capability('moodle/course:manageactivities', $context); $lifetime = null; // Check SCORM availability. if (!$canmanageactivity) { require_once $CFG->dirroot . '/mod/scorm/locallib.php'; $scorm = $DB->get_record('scorm', array('id' => $cm->instance), 'id, timeopen, timeclose', MUST_EXIST); list($available, $warnings) = scorm_get_availability_status($scorm); if (!$available) { return false; } } if ($filearea === 'content') { $revision = (int) array_shift($args); // Prevents caching problems - ignored here. $relativepath = implode('/', $args); $fullpath = "/{$context->id}/mod_scorm/content/0/{$relativepath}"; // TODO: add any other access restrictions here if needed! } else { if ($filearea === 'package') { if (!$canmanageactivity) { return false; } $revision = (int) array_shift($args); // Prevents caching problems - ignored here. $relativepath = implode('/', $args); $fullpath = "/{$context->id}/mod_scorm/package/0/{$relativepath}"; $lifetime = 0; // No caching here. } else { if ($filearea === 'imsmanifest') { // This isn't a real filearea, it's a url parameter for this type of package. $revision = (int) array_shift($args); // Prevents caching problems - ignored here. $relativepath = implode('/', $args); // Get imsmanifest file. $fs = get_file_storage(); $files = $fs->get_area_files($context->id, 'mod_scorm', 'package', 0, '', false); $file = reset($files); // Check that the package file is an imsmanifest.xml file - if not then this method is not allowed. $packagefilename = $file->get_filename(); if (strtolower($packagefilename) !== 'imsmanifest.xml') { return false; } $file->send_relative_file($relativepath); } else { return false; } } } $fs = get_file_storage(); if (!($file = $fs->get_file_by_hash(sha1($fullpath))) or $file->is_directory()) { if ($filearea === 'content') { // Return file not found straight away to improve performance. send_header_404(); die; } return false; } // Finally send the file. send_stored_file($file, $lifetime, 0, false, $options); }