function __construct($interface, $files_directory) { $field = filter_input(INPUT_POST, 'field', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); // Check for file upload. if ($field === NULL || empty($_FILES) || !isset($_FILES['file'])) { return; } $this->interface = $interface; // Create a new result object. $this->result = new stdClass(); // Set directory. $this->files_directory = $files_directory; // Create the temporary directory if it doesn't exist. $dirs = array('', '/files', '/images', '/videos', '/audios'); foreach ($dirs as $dir) { if (!H5PCore::dirReady($this->files_directory . $dir)) { $this->result->error = $this->interface->t('Unable to create directory.'); return; } } // Get the field. $this->field = json_decode($field); if (function_exists('finfo_file')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $this->type = finfo_file($finfo, $_FILES['file']['tmp_name']); finfo_close($finfo); } elseif (function_exists('mime_content_type')) { // Deprecated, only when finfo isn't available. $this->type = mime_content_type($_FILES['file']['tmp_name']); } else { $this->type = $_FILES['file']['type']; } $this->extension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION); $this->size = $_FILES['file']['size']; }
public static function handle_ajax() { global $DB, $USER; if (!\H5PCore::validToken('result', required_param('token', PARAM_RAW))) { \H5PCore::ajaxError(get_string('invalidtoken', 'hvp')); exit; } // Content parameters $content_id = required_param('contentId', PARAM_INT); $score = required_param('score', PARAM_INT); $max_score = required_param('maxScore', PARAM_INT); // Time values not usable by gradebook // $opened = required_param('opened', PARAM_INT); // $finished = required_param('finished', PARAM_INT); // Get hvp data from contentId $hvp = $DB->get_record('hvp', array('id' => $content_id)); // Check permissions $context = \context_course::instance($hvp->course); if (!has_capability('mod/hvp:saveresults', $context)) { \H5PCore::ajaxError(get_string('nopermissiontosaveresult', 'hvp')); http_response_code(403); exit; } // Create grade object and set grades $grade = (object) array('userid' => $USER->id); // Get course module id from db, required for grade item $cm_id_sql = "SELECT cm.id, h.name\n FROM {course_modules} cm, {hvp} h, {modules} m\n WHERE cm.instance = h.id AND h.id = ? AND m.name = 'hvp' AND m.id = cm.module"; $result = $DB->get_record_sql($cm_id_sql, array($content_id)); // Set grade using Gradebook API $hvp->cmidnumber = $result->id; $hvp->name = $result->name; $hvp->rawgrade = $score; $hvp->rawgrademax = $max_score; hvp_grade_item_update($hvp, $grade); // Get content info for log $content = $DB->get_record_sql("SELECT c.name AS title, l.machine_name AS name, l.major_version, l.minor_version\n FROM {hvp} c\n JOIN {hvp_libraries} l ON l.id = c.main_library_id\n WHERE c.id = ?", array($content_id)); // Log view new \mod_hvp\event('results', 'set', $content_id, $content->title, $content->name, $content->major_version . '.' . $content->minor_version); \H5PCore::ajaxSuccess(); exit; }
/** * Print results data */ public function print_results() { global $DB; // Check permission $course = $DB->get_field('hvp', 'course', array('id' => $this->content_id)); $context = \context_course::instance($course); if (!has_capability('mod/hvp:viewresults', $context)) { \H5PCore::ajaxError(get_string('nopermissiontoviewresult', 'hvp')); http_response_code(403); exit; } $results = $this->get_results(); // Make data readable for humans $rows = array(); foreach ($results as $result) { $rows[] = array(\html_writer::link(new \moodle_url('/user/view.php', array('id' => $result->user_id, 'course' => $course)), \fullname($result)), $result->rawgrade === null ? '—' : (int) $result->rawgrade, $result->rawgrade === null ? '—' : (int) $result->rawgrademax, empty($result->timemodified) ? '—' : date('Y/m/d – H:i', $result->timemodified)); } // Print header('Cache-Control: no-cache'); header('Content-type: application/json'); print json_encode(array('num' => $this->get_results_num(), 'rows' => $rows)); }
/** * Fetch library folder and save in target directory. * * @param array $library * Library properties * @param string $target * Where the library folder will be saved */ public function exportLibrary($library, $target) { $folder = \H5PCore::libraryToString($library, true); $context = \context_system::instance(); self::exportFileTree("{$target}/{$folder}", $context->id, 'libraries', "/{$folder}/"); }
} } if (empty($export)) { // Remove Download button when there's no export URL $content['disable'] |= \H5PCore::DISABLE_DOWNLOAD; } // Find cm context $context = \context_module::instance($cm->id); // Add JavaScript settings for this content. $cid = 'cid-' . $content['id']; $settings['contents'][$cid] = array('library' => \H5PCore::libraryToString($content['library']), 'jsonContent' => $safeparameters, 'fullScreen' => $content['library']['fullscreen'], 'exportUrl' => $export, 'title' => $content['title'], 'disable' => $content['disable'], 'url' => "{$CFG->httpswwwroot}/mod/hvp/view.php?id={$id}", 'contentUrl' => "{$CFG->httpswwwroot}/pluginfile.php/{$context->id}/mod_hvp/content/" . $content['id'], 'contentUserData' => array(0 => \mod_hvp\content_user_data::load_pre_loaded_user_data($content['id']))); // Get assets for this content. $preloadeddependencies = $core->loadContentDependencies($content['id'], 'preloaded'); $files = $core->getDependenciesFiles($preloadeddependencies); // Determine embed type. $embedtype = \H5PCore::determineEmbedType($content['embedType'], $content['library']['embedTypes']); if ($embedtype === 'div') { $context = \context_system::instance(); $hvppath = "/pluginfile.php/{$context->id}/mod_hvp"; // Schedule JavaScripts for loading through Moodle. foreach ($files['scripts'] as $script) { $url = $hvppath . $script->path . $script->version; $settings['loadedJs'][] = $url; $PAGE->requires->js(new moodle_url($CFG->httpswwwroot . $url), true); } // Schedule stylesheets for loading through Moodle. foreach ($files['styles'] as $style) { $url = $hvppath . $style->path . $style->version; $settings['loadedCss'][] = $url; $PAGE->requires->css(new moodle_url($CFG->httpswwwroot . $url)); }
} // Schedule stylesheets for loading through Moodle. foreach ($files['styles'] as $style) { $url = $hvppath . $style->path . $style->version; $settings['loadedCss'][] = $url; $PAGE->requires->css(new moodle_url($CFG->httpswwwroot . $url)); } } else { // JavaScripts and stylesheets will be loaded through h5p.js. $settings['contents'][$cid]['scripts'] = $core->getAssetsUrls($files['scripts']); $settings['contents'][$cid]['styles'] = $core->getAssetsUrls($files['styles']); } // Print JavaScript settings to page. $PAGE->requires->data_for_js('H5PIntegration', $settings, true); // H5P JS xAPI event listener & Moodle event log dispatcher. $jsparams = array('hvpid' => $id, 'courseid' => $course->id, 'debug' => $CFG->debug, 'token' => \H5PCore::createToken('logxapievent')); $PAGE->requires->js_call_amd('mod_hvp/xapi-stmt-dispatcher', 'init', array($jsparams)); // Print page HTML. echo $OUTPUT->header(); echo $OUTPUT->heading(format_string($content['title'])); echo '<div class="clearer"></div>'; // Print any messages. \mod_hvp\framework::printMessages('info', \mod_hvp\framework::messages('info')); \mod_hvp\framework::printMessages('error', \mod_hvp\framework::messages('error')); // Print intro. if (trim(strip_tags($content['intro']))) { echo $OUTPUT->box_start('mod_introbox', 'hvpintro'); echo format_module_intro('hvp', (object) array('intro' => $content['intro'], 'introformat' => $content['introformat']), $cm->id); echo $OUTPUT->box_end(); } // Print H5P Content
/** * Include settings and assets for the given content. * * @since 1.0.0 * @param array $content * @param boolean $no_cache * @return string Embed code */ public function add_assets($content, $no_cache = FALSE) { // Add core assets $this->add_core_assets(); // Detemine embed type $embed = H5PCore::determineEmbedType($content['embedType'], $content['library']['embedTypes']); // Make sure content isn't added twice $cid = 'cid-' . $content['id']; if (!isset(self::$settings['contents'][$cid])) { self::$settings['contents'][$cid] = $this->get_content_settings($content); $core = $this->get_h5p_instance('core'); // Get assets for this content $preloaded_dependencies = $core->loadContentDependencies($content['id'], 'preloaded'); $files = $core->getDependenciesFiles($preloaded_dependencies); $this->alter_assets($files, $preloaded_dependencies, $embed); if ($embed === 'div') { $this->enqueue_assets($files); } elseif ($embed === 'iframe') { self::$settings['contents'][$cid]['scripts'] = $core->getAssetsUrls($files['scripts']); self::$settings['contents'][$cid]['styles'] = $core->getAssetsUrls($files['styles']); } } if ($embed === 'div') { return '<div class="h5p-content" data-content-id="' . $content['id'] . '"></div>'; } else { return '<div class="h5p-iframe-wrapper"><iframe id="h5p-iframe-' . $content['id'] . '" class="h5p-iframe" data-content-id="' . $content['id'] . '" style="height:1px" src="about:blank" frameBorder="0" scrolling="no"></iframe></div>'; } }
/** * Process a single field. * * @staticvar string $h5peditor_path * @param object $field * @param mixed $params * @param array $files */ private function processField(&$field, &$params, &$files) { switch ($field->type) { case 'file': case 'image': if (isset($params->path)) { $this->processFile($params, $files); // Process original image if (isset($params->originalImage) && isset($params->originalImage->path)) { $this->processFile($params->originalImage, $files); } } break; case 'video': case 'audio': if (is_array($params)) { for ($i = 0, $s = count($params); $i < $s; $i++) { $this->processFile($params[$i], $files); } } break; case 'library': if (isset($params->library) && isset($params->params)) { $library = H5PCore::libraryFromString($params->library); $semantics = $this->h5p->loadLibrarySemantics($library['machineName'], $library['majorVersion'], $library['minorVersion']); // Process parameters for the library. $this->processSemantics($files, $semantics, $params->params); } break; case 'group': if (isset($params)) { if (count($field->fields) == 1) { $params = (object) array($field->fields[0]->name => $params); } $this->processSemantics($files, $field->fields, $params); } break; case 'list': if (is_array($params)) { for ($j = 0, $t = count($params); $j < $t; $j++) { $this->processField($field->field, $params[$j], $files); } } break; } }
/** * Validate given library value against library semantics. * Check if provided library is within allowed options. * * Will recurse into validating the library's semantics too. */ public function validateLibrary(&$value, $semantics) { if (!isset($value->library) || !in_array($value->library, $semantics->options)) { $this->h5pF->setErrorMessage($this->h5pF->t('Library used in content is not a valid library according to semantics')); $value = new stdClass(); return; } if (!isset($this->libraries[$value->library])) { $libspec = H5PCore::libraryFromString($value->library); $library = $this->h5pC->loadLibrary($libspec['machineName'], $libspec['majorVersion'], $libspec['minorVersion']); $library['semantics'] = $this->h5pC->loadLibrarySemantics($libspec['machineName'], $libspec['majorVersion'], $libspec['minorVersion']); $this->libraries[$value->library] = $library; } else { $library = $this->libraries[$value->library]; } $this->validateGroup($value->params, (object) array('type' => 'group', 'fields' => $library['semantics']), FALSE); $validkeys = array('library', 'params'); if (isset($semantics->extraAttributes)) { $validkeys = array_merge($validkeys, $semantics->extraAttributes); } $this->filterParams($value, $validkeys); // Find all dependencies for this library $depkey = 'preloaded-' . $library['machineName']; if (!isset($this->dependencies[$depkey])) { $this->dependencies[$depkey] = array('library' => $library, 'type' => 'preloaded'); $this->nextWeight = $this->h5pC->findLibraryDependencies($this->dependencies, $library, $this->nextWeight); $this->dependencies[$depkey]['weight'] = $this->nextWeight++; } }
FROM {hvp_libraries} hl1 JOIN {hvp_libraries} hl2 ON hl1.machine_name = hl2.machine_name WHERE hl1.id = ? ORDER BY hl2.title ASC, hl2.major_version ASC, hl2.minor_version ASC', array($libraryid)); $versions = array(); foreach ($results as $result) { $versions[$result->id] = $result; } $library = $versions[$libraryid]; $upgrades = $core->getUpgrades($library, $versions); $PAGE->set_heading(get_string('upgradeheading', 'hvp', $library->title . ' (' . \H5PCore::libraryVersion($library) . ')')); // Get num of contents that can be upgraded. $numcontents = $core->h5pF->getNumContent($libraryid); if (count($versions) < 2) { echo $OUTPUT->header(); echo get_string('upgradenoavailableupgrades', 'hvp'); } else { if ($numcontents === 0) { echo $OUTPUT->header(); echo get_string('upgradenothingtodo', 'hvp'); } else { $settings = array('libraryInfo' => array('message' => get_string('upgrademessage', 'hvp', $numcontents), 'inProgress' => get_string('upgradeinprogress', 'hvp'), 'error' => get_string('upgradeerror', 'hvp'), 'errorData' => get_string('upgradeerrordata', 'hvp'), 'errorScript' => get_string('upgradeerrorscript', 'hvp'), 'errorContent' => get_string('upgradeerrorcontent', 'hvp'), 'errorParamsBroken' => get_string('upgradeerrorparamsbroken', 'hvp'), 'done' => get_string('upgradedone', 'hvp', $numcontents) . ' <a href="' . (new moodle_url('/mod/hvp/library_list.php'))->out(false) . '">' . get_string('upgradereturn', 'hvp') . '</a>', 'library' => array('name' => $library->name, 'version' => $library->major_version . '.' . $library->minor_version), 'libraryBaseUrl' => (new moodle_url('/mod/hvp/ajax.php', array('action' => 'getlibrarydataforupgrade')))->out(false) . '&library=', 'scriptBaseUrl' => (new moodle_url('/mod/hvp/library/js'))->out(false), 'buster' => hvp_get_cache_buster(), 'versions' => $upgrades, 'contents' => $numcontents, 'buttonLabel' => get_string('upgradebuttonlabel', 'hvp'), 'infoUrl' => (new moodle_url('/mod/hvp/ajax.php', array('action' => 'libraryupgradeprogress', 'library_id' => $libraryid)))->out(false), 'total' => $numcontents, 'token' => \H5PCore::createToken('contentupgrade'))); // Add JavaScripts. $liburl = $CFG->httpswwwroot . '/mod/hvp/library/'; hvp_admin_add_generic_css_and_js($PAGE, $liburl, $settings); $PAGE->requires->js(new moodle_url($liburl . 'js/h5p-version.js' . hvp_get_cache_buster()), true); $PAGE->requires->js(new moodle_url($liburl . 'js/h5p-content-upgrade.js' . hvp_get_cache_buster()), true); echo $OUTPUT->header(); echo '<div id="h5p-admin-container">' . get_string('enablejavascript', 'hvp') . '</div>'; } } echo $OUTPUT->footer();
global $CFG; // Trigger a Moodle log event for each xAPI statement // that is dispatched by the H5P (hvp) object. if (!\H5PCore::validToken('logxapievent', required_param('token', PARAM_RAW))) { \H5PCore::ajaxError(get_string('invalidtoken', 'hvp')); exit; } $hvpid = optional_param('hvpid', null, PARAM_INT); $courseid = optional_param('courseid', null, PARAM_INT); $jsonxapistatement = optional_param('xapistatement', null, PARAM_RAW); $xapistatement = json_decode($jsonxapistatement, true); $context = \context_module::instance($hvpid); $event = \mod_hvp\event\hvp_xapi::create(array('objectid' => $hvpid, 'context' => $context, 'other' => array('statement' => $xapistatement['data']['statement']), 'courseid' => $courseid)); $event->trigger(); // Debugging... if (!empty($CFG->debug) and $CFG->debug >= DEBUG_DEVELOPER) { $msg = "xAPI '" . $xapistatement['data']['statement']['verb']['display']['en-US'] . "' statement dispatched"; \H5PCore::ajaxSuccess($msg); http_response_code(200); } break; /* * Throw error if AJAX isnt handeled */ /* * Throw error if AJAX isnt handeled */ default: throw new coding_exception('Unhandled AJAX'); break; }
/** * Implements deleteLibrary */ public function deleteLibrary($library) { global $wpdb; // Delete library files H5PCore::deleteFileTree($this->getH5pPath() . '/libraries/' . $library->name . '-' . $library->major_version . '.' . $library->minor_version); // Remove library data from database $wpdb->delete($wpdb->prefix . 'h5p_libraries_libraries', array('library_id' => $library->id), array('%d')); $wpdb->delete($wpdb->prefix . 'h5p_libraries_languages', array('library_id' => $library->id), array('%d')); $wpdb->delete($wpdb->prefix . 'h5p_libraries', array('id' => $library->id), array('%d')); }
/** * Handle user results reported by the H5P content. * * @since 1.5.0 */ public function ajax_contents_user_data() { global $wpdb; $content_id = filter_input(INPUT_GET, 'content_id'); $data_id = filter_input(INPUT_GET, 'data_type'); $sub_content_id = filter_input(INPUT_GET, 'sub_content_id'); $current_user = wp_get_current_user(); if ($content_id === NULL || $data_id === NULL || $sub_content_id === NULL || !$current_user->ID) { return; // Missing parameters } $response = (object) array('success' => TRUE); $data = filter_input(INPUT_POST, 'data'); $preload = filter_input(INPUT_POST, 'preload'); $invalidate = filter_input(INPUT_POST, 'invalidate'); if ($data !== NULL && $preload !== NULL && $invalidate !== NULL) { if (!wp_verify_nonce(filter_input(INPUT_POST, 'token'), 'h5p_contentuserdata')) { H5PCore::ajaxError(__('Invalid security token', $this->plugin_slug)); exit; } if ($data === '0') { // Remove data $wpdb->delete($wpdb->prefix . 'h5p_contents_user_data', array('content_id' => $content_id, 'data_id' => $data_id, 'user_id' => $current_user->ID, 'sub_content_id' => $sub_content_id), array('%d', '%s', '%d', '%d')); } else { // Wash values to ensure 0 or 1. $preload = $preload === '0' ? 0 : 1; $invalidate = $invalidate === '0' ? 0 : 1; // Determine if we should update or insert $update = $wpdb->get_var($wpdb->prepare("SELECT content_id\n FROM {$wpdb->prefix}h5p_contents_user_data\n WHERE content_id = %d\n AND user_id = %d\n AND data_id = %s\n AND sub_content_id = %d", $content_id, $current_user->ID, $data_id, $sub_content_id)); if ($update === NULL) { // Insert new data $wpdb->insert($wpdb->prefix . 'h5p_contents_user_data', array('user_id' => $current_user->ID, 'content_id' => $content_id, 'sub_content_id' => $sub_content_id, 'data_id' => $data_id, 'data' => $data, 'preload' => $preload, 'invalidate' => $invalidate, 'updated_at' => current_time('mysql', 1)), array('%d', '%d', '%d', '%s', '%s', '%d', '%d', '%s')); } else { // Update old data $wpdb->update($wpdb->prefix . 'h5p_contents_user_data', array('data' => $data, 'preload' => $preload, 'invalidate' => $invalidate, 'updated_at' => current_time('mysql', 1)), array('user_id' => $current_user->ID, 'content_id' => $content_id, 'data_id' => $data_id, 'sub_content_id' => $sub_content_id), array('%s', '%d', '%d', '%s'), array('%d', '%d', '%s', '%d')); } } // Inserted, updated or deleted H5PCore::ajaxSuccess(); exit; } else { // Fetch data $response->data = $wpdb->get_var($wpdb->prepare("SELECT hcud.data\n FROM {$wpdb->prefix}h5p_contents_user_data hcud\n WHERE user_id = %d\n AND content_id = %d\n AND data_id = %s\n AND sub_content_id = %d", $current_user->ID, $content_id, $data_id, $sub_content_id)); if ($response->data === NULL) { unset($response->data); } } header('Cache-Control: no-cache'); header('Content-type: application/json; charset=utf-8'); print json_encode($response); exit; }
/** * Handle content upgrade progress * * @method hvp_content_upgrade_progress * @param int $library_id * @return object An object including the json content for the H5P instances * (maximum 40) that should be upgraded. */ function hvp_content_upgrade_progress($libraryid) { global $DB; $tolibraryid = filter_input(INPUT_POST, 'libraryId'); // Verify security token. if (!\H5PCore::validToken('contentupgrade', required_param('token', PARAM_RAW))) { print get_string('upgradeinvalidtoken', 'hvp'); return; } // Get the library we're upgrading to. $tolibrary = $DB->get_record('hvp_libraries', array('id' => $tolibraryid)); if (!$tolibrary) { print get_string('upgradelibrarymissing', 'hvp'); return; } // Prepare response. $out = new stdClass(); $out->params = array(); $out->token = \H5PCore::createToken('contentupgrade'); // Prepare our interface. $interface = \mod_hvp\framework::instance('interface'); // Get updated params. $params = filter_input(INPUT_POST, 'params'); if ($params !== null) { // Update params. $params = json_decode($params); foreach ($params as $id => $param) { $DB->update_record('hvp', (object) array('id' => $id, 'main_library_id' => $tolibrary->id, 'json_content' => $param, 'filtered' => '')); // Log content upgrade successful new \mod_hvp\event('content', 'upgrade', $id, $DB->get_field_sql("SELECT name FROM {hvp} WHERE id = ?", array($id)), $tolibrary->machine_name, $tolibrary->major_version . '.' . $tolibrary->minor_version); } } // Get number of contents for this library. $out->left = $interface->getNumContent($libraryid); if ($out->left) { // Find the 40 first contents using this library version and add to params. $results = $DB->get_records_sql("SELECT id, json_content as params\n FROM {hvp}\n WHERE main_library_id = ?\n ORDER BY name ASC", array($libraryid), 0, 40); foreach ($results as $content) { $out->params[$content->id] = $content->params; } } return $out; }
/** * Handle file uploads through AJAX. * * @since 1.1.0 */ public function ajax_files() { $plugin = H5P_Plugin::get_instance(); $files_directory = $plugin->get_h5p_path(); if (!wp_verify_nonce(filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING), 'h5p_editor_ajax')) { H5PCore::ajaxError(__('Invalid security token. Please reload the editor.', $this->plugin_slug)); exit; } $contentId = filter_input(INPUT_POST, 'contentId', FILTER_SANITIZE_NUMBER_INT); if ($contentId) { $files_directory .= '/content/' . $contentId; } else { $files_directory .= '/editor'; } $editor = $this->get_h5peditor_instance(); $interface = $plugin->get_h5p_instance('interface'); $file = new H5peditorFile($interface, $files_directory); if (!$file->isLoaded()) { H5PCore::ajaxError(__('File not found on server. Check file upload settings.', $this->plugin_slug)); exit; } if ($file->validate() && $file->copy()) { // Keep track of temporary files so they can be cleaned up later. $editor->addTmpFile($file); } header('Cache-Control: no-cache'); // Must support IE, so cannot use application/json header('Content-type: text/plain; charset=utf-8'); print $file->getResult(); exit; }
/** * Does the actual process of saving the H5P content that's submitted through * the activity form * * @param stdClass $hvp * @return int Content ID */ function hvp_save_content($hvp) { // Determine disabled content features $hvp->disable = hvp_get_disabled_content_features($hvp); // Determine if we're uploading or creating if ($hvp->h5paction === 'upload') { // Save uploaded package $hvp->uploaded = true; $h5pstorage = \mod_hvp\framework::instance('storage'); $h5pstorage->savePackage((array) $hvp); $hvp->id = $h5pstorage->contentId; } else { // Save newly created or edited content $core = \mod_hvp\framework::instance(); $editor = \mod_hvp\framework::instance('editor'); if (!empty($hvp->id)) { // Load existing content to get old parameters for comparison $content = $core->loadContent($hvp->id); $oldlib = $content['library']; $oldparams = json_decode($content['params']); } // Make params and library available for core to save $hvp->params = $hvp->h5pparams; $hvp->library = H5PCore::libraryFromString($hvp->h5plibrary); $hvp->library['libraryId'] = $core->h5pF->getLibraryId($hvp->library['machineName'], $hvp->library['majorVersion'], $hvp->library['minorVersion']); $hvp->id = $core->saveContent((array) $hvp); // We need to process the parameters to move any images or files and // to determine which dependencies the content has. // Prepare current parameters $params = json_decode($hvp->params); // Move any uploaded images or files. Determine content dependencies. $editor->processParameters($hvp->id, $hvp->library, $params, isset($oldlib) ? $oldlib : NULL, isset($oldparams) ? $oldparams : NULL); } return $hvp->id; }
$settings = array(); $i = 0; foreach ($libraries as $versions) { foreach ($versions as $library) { $usage = $core->h5pF->getLibraryUsage($library->id, $numNotFiltered ? true : false); if ($library->runnable) { $upgrades = $core->getUpgrades($library, $versions); $upgradeUrl = empty($upgrades) ? false : (new moodle_url('/mod/hvp/upgrade_content_page.php', array('library_id' => $library->id)))->out(false); $restricted = isset($library->restricted) && $library->restricted == 1 ? true : false; $restricted_url = (new moodle_url('/mod/hvp/ajax.php', array('action' => 'restrict_library', 'token' => \H5PCore::createToken('library_' . $library->id), 'restrict' => $restricted ? 0 : 1, 'library_id' => $library->id)))->out(false); } else { $upgradeUrl = null; $restricted = null; $restricted_url = null; } $settings['libraryList']['listData'][] = array('title' => $library->title . ' (' . \H5PCore::libraryVersion($library) . ')', 'restricted' => $restricted, 'restrictedUrl' => $restricted_url, 'numContent' => $core->h5pF->getNumContent($library->id), 'numContentDependencies' => $usage['content'] === -1 ? '' : $usage['content'], 'numLibraryDependencies' => $usage['libraries'], 'upgradeUrl' => $upgradeUrl, 'detailsUrl' => null, 'deleteUrl' => null); $i++; } } // All translations are made server side $settings['libraryList']['listHeaders'] = array(get_string('librarylisttitle', 'hvp'), get_string('librarylistrestricted', 'hvp'), get_string('librarylistinstances', 'hvp'), get_string('librarylistinstancedependencies', 'hvp'), get_string('librarylistlibrarydependencies', 'hvp'), get_string('librarylistactions', 'hvp')); // Add js $lib_url = $CFG->httpswwwroot . '/mod/hvp/library/'; hvp_admin_add_generic_css_and_js($PAGE, $lib_url, $settings); $PAGE->requires->js(new moodle_url($lib_url . 'js/h5p-library-list.js' . hvp_get_cache_buster()), true); // RENDER PAGE OUTPUT echo $OUTPUT->header(); // Print any messages \mod_hvp\framework::printMessages('info', \mod_hvp\framework::messages('info')); \mod_hvp\framework::printMessages('error', \mod_hvp\framework::messages('error')); // Page Header
/** * Process a single field. * * @staticvar string $h5peditor_path * @param object $field * @param mixed $params * @param array $files * @param array $libraries */ private function processField(&$field, &$params, &$files) { static $h5peditor_path; if (!$h5peditor_path) { $h5peditor_path = $this->editorFilesDir . DIRECTORY_SEPARATOR; } switch ($field->type) { case 'file': case 'image': if (isset($params->path)) { $oldPath = $h5peditor_path . $params->path; $newPath = $this->content_directory . $params->path; if (file_exists($oldPath)) { rename($oldPath, $newPath); $this->storage->keepFile($oldPath, $newPath); } elseif (file_exists($newPath)) { $this->storage->keepFile($newPath, $newPath); } $files[] = $params->path; } break; case 'video': case 'audio': if (is_array($params)) { for ($i = 0, $s = count($params); $i < $s; $i++) { $oldPath = $h5peditor_path . $params[$i]->path; $newPath = $this->content_directory . $params[$i]->path; if (file_exists($oldPath)) { rename($oldPath, $newPath); $this->storage->keepFile($oldPath, $newPath); } elseif (file_exists($newPath)) { $this->storage->keepFile($newPath, $newPath); } $files[] = $params[$i]->path; } } break; case 'library': if (isset($params->library) && isset($params->params)) { $library = H5PCore::libraryFromString($params->library); $semantics = $this->h5p->loadLibrarySemantics($library['machineName'], $library['majorVersion'], $library['minorVersion']); // Process parameters for the library. $this->processSemantics($files, $semantics, $params->params); } break; case 'group': if (isset($params)) { if (count($field->fields) == 1) { $params = (object) array($field->fields[0]->name => $params); } $this->processSemantics($files, $field->fields, $params); } break; case 'list': if (is_array($params)) { for ($j = 0, $t = count($params); $j < $t; $j++) { $this->processField($field->field, $params[$j], $files); } } break; } }
/** * Fetch library folder and save in target directory. * * @param array $library * Library properties * @param string $target * Where the library folder will be saved * @param string $developmentPath * Folder that library resides in */ public function exportLibrary($library, $target, $developmentPath = NULL) { $folder = \H5PCore::libraryToString($library, TRUE); $srcPath = $developmentPath === NULL ? "/libraries/{$folder}" : $developmentPath; self::copyFileTree("{$this->path}{$srcPath}", "{$target}/{$folder}"); }
/** * Display details for a given content library. * * @since 1.1.0 */ private function display_library_details() { global $wpdb; $library = $this->get_library(); H5P_Plugin_Admin::print_messages(); if (!$library) { return; } // Add settings and translations $plugin = H5P_Plugin::get_instance(); $interface = $plugin->get_h5p_instance('interface'); $settings = array('containerSelector' => '#h5p-admin-container'); // Build the translations needed $settings['libraryInfo']['translations'] = array('noContent' => __('No content is using this library', $this->plugin_slug), 'contentHeader' => __('Content using this library', $this->plugin_slug), 'pageSizeSelectorLabel' => __('Elements per page', $this->plugin_slug), 'filterPlaceholder' => __('Filter content', $this->plugin_slug), 'pageXOfY' => __('Page $x of $y', $this->plugin_slug)); $notCached = $interface->getNumNotFiltered(); if ($notCached) { $settings['libraryInfo']['notCached'] = $this->get_not_cached_settings($notCached); } else { // List content which uses this library $contents = $wpdb->get_results($wpdb->prepare("SELECT DISTINCT hc.id, hc.title\n FROM {$wpdb->prefix}h5p_contents_libraries hcl\n JOIN {$wpdb->prefix}h5p_contents hc ON hcl.content_id = hc.id\n WHERE hcl.library_id = %d\n ORDER BY hc.title", $library->id)); foreach ($contents as $content) { $settings['libraryInfo']['content'][] = array('title' => $content->title, 'url' => admin_url('admin.php?page=h5p&task=show&id=' . $content->id)); } } // Build library info $settings['libraryInfo']['info'] = array(__('Version', $this->plugin_slug) => H5PCore::libraryVersion($library), __('Fullscreen', $this->plugin_slug) => $library->fullscreen ? __('Yes', $this->plugin_slug) : __('No', $this->plugin_slug), __('Content library', $this->plugin_slug) => $library->runnable ? __('Yes', $this->plugin_slug) : __('No', $this->plugin_slug), __('Used by', $this->plugin_slug) => isset($contents) ? sprintf(_n('1 content', '%d contents', count($contents), $this->plugin_slug), count($contents)) : __('N/A', $this->plugin_slug)); $this->add_admin_assets(); H5P_Plugin_Admin::add_script('library-list', 'h5p-php-library/js/h5p-library-details.js'); include_once 'views/library-details.php'; $plugin->print_settings($settings, 'H5PAdminIntegration'); }
/** * Extract disabled content features from input post. * * @since 1.2.0 * @param H5PCore $core * @param int $current * @return int */ private function get_disabled_content_features($core, &$content) { $set = array('frame' => filter_input(INPUT_POST, 'frame', FILTER_VALIDATE_BOOLEAN), 'download' => filter_input(INPUT_POST, 'download', FILTER_VALIDATE_BOOLEAN), 'embed' => filter_input(INPUT_POST, 'embed', FILTER_VALIDATE_BOOLEAN), 'copyright' => filter_input(INPUT_POST, 'copyright', FILTER_VALIDATE_BOOLEAN)); $content['disable'] = $core->getDisable($set, $content['disable']); }
/** * Implements loadContentDependencies */ public function loadContentDependencies($id, $type = null) { global $DB; $query = "SELECT hcl.id AS unidepid\n , hl.id\n , hl.machine_name\n , hl.major_version\n , hl.minor_version\n , hl.patch_version\n , hl.preloaded_css\n , hl.preloaded_js\n , hcl.drop_css\n , hcl.dependency_type\n FROM {hvp_contents_libraries} hcl\n JOIN {hvp_libraries} hl ON hcl.library_id = hl.id\n WHERE hcl.hvp_id = ?"; $queryArgs = array($id); if ($type !== null) { $query .= " AND hcl.dependency_type = ?"; $queryArgs[] = $type; } $query .= " ORDER BY hcl.weight"; $data = $DB->get_records_sql($query, $queryArgs); $dependencies = array(); foreach ($data as $dependency) { unset($dependency->unidepid); $dependencies[] = \H5PCore::snakeToCamel($dependency); } return $dependencies; }
* int contextId */ case 'files': global $DB; // TODO: Check permissions if (!\H5PCore::validToken('editorajax', required_param('token', PARAM_RAW))) { \H5PCore::ajaxError(get_string('invalidtoken', 'hvp')); exit; } // Get Content ID and Context ID for upload $contentid = required_param('contentId', PARAM_INT); $contextid = required_param('contextId', PARAM_INT); // Create file $file = new H5peditorFile(\mod_hvp\framework::instance('interface')); if (!$file->isLoaded()) { H5PCore::ajaxError(get_string('filenotfound', 'hvp')); break; } // Make sure file is valid if ($file->validate()) { $core = \mod_hvp\framework::instance('core'); // Save the valid file $file_id = $core->fs->saveFile($file, $contentid, $contextid); // Track temporary files for later cleanup $DB->insert_record_raw('hvp_tmpfiles', array('id' => $file_id), false, false, true); } $file->printResult(); break; /* * Throw error if AJAX isnt handeled */
public function validation($data, $files) { global $CFG; $errors = parent::validation($data, $files); if ($data['h5paction'] === 'upload') { // Validate uploaded H5P file if (empty($data['h5pfile'])) { // Field missing $errors['h5pfile'] = get_string('required'); } else { $files = $this->get_draft_files('h5pfile'); if (count($files) < 1) { // No file uploaded $errors['h5pfile'] = get_string('required'); } else { // Prepare to validate package $file = reset($files); $interface = \mod_hvp\framework::instance('interface'); $path = $CFG->tempdir . uniqid('/hvp-'); $interface->getUploadedH5pFolderPath($path); $path .= '.h5p'; $interface->getUploadedH5pPath($path); $file->copy_content_to($path); $h5pvalidator = \mod_hvp\framework::instance('validator'); if (!$h5pvalidator->isValidPackage()) { // Errors while validating the package $infomessages = implode('<br/>', \mod_hvp\framework::messages('info')); $errormessages = implode('<br/>', \mod_hvp\framework::messages('error')); $errors['h5pfile'] = ($errormessages ? $errormessages . '<br/>' : '') . $infomessages; } } } } else { // Validate library and params used in editor $core = \mod_hvp\framework::instance(); // Get library array from string $library = H5PCore::libraryFromString($data['h5plibrary']); if (!$library) { $errors['h5peditor'] = get_string('invalidlibrary', 'hvp'); } else { // Check that library exists $library['libraryId'] = $core->h5pF->getLibraryId($library['machineName'], $library['majorVersion'], $library['minorVersion']); if (!$library['libraryId']) { $errors['h5peditor'] = get_string('nosuchlibrary', 'hvp'); } else { $data['h5plibrary'] = $library; // Verify that parameters are valid if (empty($data['h5pparams'])) { $errors['h5peditor'] = get_string('noparameters', 'hvp'); } else { $params = json_decode($data['h5pparams']); if ($params === NULL) { $errors['h5peditor'] = get_string('invalidparameters', 'hvp'); } else { $data['h5pparams'] = $params; } } } } } return $errors; }
/** * Retrieves ajax parameters for content and update or delete * user data depending on params. * * @throws \coding_exception */ public static function handle_ajax() { global $DB; // Query String Parameters. $content_id = required_param('content_id', PARAM_INT); $data_id = required_param('data_type', PARAM_RAW); $sub_content_id = required_param('sub_content_id', PARAM_INT); // Form Data. $data = optional_param('data', null, PARAM_RAW); $pre_load = optional_param('preload', null, PARAM_INT); $invalidate = optional_param('invalidate', null, PARAM_INT); if ($content_id === null || $data_id === null || $sub_content_id === null) { \H5PCore::ajaxError(get_string('missingparameters', 'hvp')); exit; // Missing parameters. } // Saving data if ($data !== NULL && $pre_load !== NULL && $invalidate !== NULL) { // Validate token if (!\H5PCore::validToken('contentuserdata', required_param('token', PARAM_RAW))) { \H5PCore::ajaxError(get_string('invalidtoken', 'hvp')); exit; } // Use context id if supplied $context_id = optional_param('contextId', null, PARAM_INT); if ($context_id) { $context = \context::instance_by_id($context_id); } else { // Otherwise try to find it from content id $context = \context_course::instance($DB->get_field('hvp', 'course', array('id' => $content_id))); } // Check permissions if (!has_capability('mod/hvp:savecontentuserdata', $context)) { \H5PCore::ajaxError(get_string('nopermissiontosavecontentuserdata', 'hvp')); http_response_code(403); exit; } if ($data === '0') { // Delete user data. self::delete_user_data($content_id, $sub_content_id, $data_id); } else { // Save user data. self::save_user_data($content_id, $sub_content_id, $data_id, $pre_load, $invalidate, $data); } \H5PCore::ajaxSuccess(); } else { // Fetch user data $user_data = self::get_user_data($content_id, $sub_content_id, $data_id); if ($user_data === false) { // Did not find data, return nothing \H5PCore::ajaxSuccess(); } else { // Found data, return encoded data \H5PCore::ajaxSuccess($user_data->data); } } exit; }